My Androidアプリは、情報を渡すインテント(ステータスバーのペンディングインテント)によって呼び出されます。
ホームボタンを押してホームボタンを押したままアプリを再度開くと、再びインテントが呼び出され、同じエキストラがまだそこにあります。
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
これは想定されたように実行されないコードです
String imgUrl;
Bundle extras = this.getIntent().getExtras();
if(extras != null){
imgUrl = extras.getString("imgUrl");
if( !imgUrl.equals(textView01.getText().toString()) ){
imageView.setImageDrawable( getImageFromUrl( imgUrl ) );
layout1.setVisibility(0);
textView01.setText(imgUrl);//textview to hold the url
}
}
そして、私の意図:
public void showNotification(String ticker, String title, String message,
String imgUrl){
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(ns);
int icon = R.drawable.icon; // icon from resources
long when = System.currentTimeMillis(); // notification time
CharSequence tickerText = ticker; // ticker-text
//make intent
Intent notificationIntent = new Intent(this, activity.class);
notificationIntent.putExtra("imgUrl", imgUrl);
notificationIntent.setFlags(
PendingIntent.FLAG_UPDATE_CURRENT |
PendingIntent.FLAG_ONE_SHOT);
PendingIntent contentIntent =
PendingIntent.getActivity(this, 0,
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT |
PendingIntent.FLAG_ONE_SHOT);
//make notification
Notification notification = new Notification(icon, tickerText, when);
notification.setLatestEventInfo(this, title, message, contentIntent);
//flags
notification.flags = Notification.FLAG_SHOW_LIGHTS |
Notification.FLAG_ONGOING_EVENT |
Notification.FLAG_ONLY_ALERT_ONCE |
Notification.FLAG_AUTO_CANCEL;
//sounds
notification.defaults |= Notification.DEFAULT_SOUND;
//notify
mNotificationManager.notify(1, notification);
}
意図をクリアする方法、または以前に使用されたことがあるかどうかを確認する方法はありますか?
5年前に初めてこの回答を書いたとき、この回答がそれほど言及されているとは思いませんでした!
@ tato-rodrigoの回答によると、これは状況によっては既に処理された意図を検出するのに役立たないことを指摘するために明確にします。
また、私は理由のために引用符で「クリア」を入れたことを指摘する必要があります-あなたはnotこれを行うことで意図を本当にクリアしています、あなたはこの意図のフラグとして余分なものの削除を使用しているだけですすでにアクティビティで見られています。
私はまったく同じ問題を抱えていました。
上記の答えは私を正しい軌道に乗せ、さらに簡単な解決策を見つけました:
getIntent().removeExtra("key");
インテントを「クリア」するメソッド呼び出し。
これは1年前に質問されてから少し遅れて回答しましたが、将来的に他の人の助けになることを願っています。
編集:使用している完全なソリューションを投稿するために編集しています。
このソリューションは、問題が「アクティビティが履歴(最近のアプリ)から始まるときに一部のコードを実行しない」の場合に機能します。
まず、boolean
でActivity
を宣言して、Intent
がすでに消費されているかどうかを示します。
private boolean consumedIntent;
次に、onSaveInstanceState
メソッドとonCreate
メソッドを使用してこの値を安全に保存および復元し、構成の変更と、システムがバックグラウンドに移行したときにActivity
を強制終了する場合を処理します。
private final String SAVED_INSTANCE_STATE_CONSUMED_INTENT = "SAVED_INSTANCE_STATE_CONSUMED_INTENT";
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(SAVED_INSTANCE_STATE_CONSUMED_INTENT, consumedIntent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//set content view ...
if( savedInstanceState != null ) {
consumedIntent = savedInstanceState.getBoolean(SAVED_INSTANCE_STATE_CONSUMED_INTENT);
}
//other initializations
}
次に、onResume
メソッドでコードを実行できるかどうかを確認します。
@Override
protected void onResume() {
super.onResume();
//check if this intent should run your code
//for example, check the Intent action
boolean shouldThisIntentTriggerMyCode = [...];
Intent intent = getIntent();
boolean launchedFromHistory = intent != null ? (intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0 : false;
if( !launchedFromHistory && shouldThisIntentTriggerMyCode && !consumedIntent ) {
consumedIntent = true;
//execute the code that should be executed if the activity was not launched from history
}
}
さらに、Activity
がsingleTop
に設定されている場合、新しいIntent
が配信されたときにフラグをリセットする必要があります。
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
consumedIntent = false;
}
Maksの回答は、余分なものをクリアするために機能します。
getIntent().removeExtra("key");
別の便利なコマンドは次のとおりです。
getIntent().setAction("");
以下を呼び出すことでインテントにタグを付けることもできます。
getIntent().putExtra("used", true);
次に値を確認します。
Android History(Recent Apps)のアプリ)を起動すると、主に3つの異なるIntentフラグでアプリを起動できます。
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
_FLAG_ACTIVITY_NEW_TASK
_FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY | FLAG_ACTIVITY_NEW_TASK
_定数値はgetIntent().getFlags()
経由で取得できます
3番目のケースでは、Androidはメモリから最後のIntent値をリロードします。したがって、アプリのインテント(getIntent
)は、アプリを起動した最後のインテントの値を持ちます。
実際には、アプリはあたかも新しい起動のように動作する必要があり、前回の起動の意図値ではなく、新しい起動の意図値を使用します。 アプリのアイコンをクリックしてアプリを起動すると、この動作が見られます。古いインテント値はありません。これは、Androidはこのシナリオで次のインテントフィルターを使用するためです
_ <intent-filter>
<action Android:name="Android.intent.action.MAIN" />
<category Android:name="Android.intent.category.LAUNCHER"/>
</intent-filter>
_
ただし、3番目の場合(終了したアプリは、最近のアプリの履歴から起動されます)、Android OSは、(戻るボタンを押して)終了する前にアプリを起動した最後のインテントを使用します。そのため、最終的にはインテント値が古いことになり、アプリのフローは適切ではありません。
意図を削除することはそれを解決する1つの方法ですが、問題を完全に解決することはできません! As Android OSは、起動インテントの最後のインスタンスではなく、アプリの最後の起動からインテントをリロードします。
これを避けるためのクリーンな方法は、タイプ Intent を取得して起動タイプを決定することで処理することです。
したがって、LaunchActivity(マニフェストでインテントフィルターが定義されているもの)では、onCreate()
、onStart()
、またはonResume()
で次のコードを使用できます。メソッド。
_if(getIntent().getFlags() == (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)) {
//app is launched from recent apps after it was closed
normalLaunch();
} else {
String intentAction = getIntent().getAction();
String scheme = getIntent().getScheme();
//app is launched via other means
// URL intent scheme, Intent action etc
if("https".equalsIgnoreCase(scheme)) {
// URL intent for browser
} else if("com.example.bb".equalsIgnoreCase(intentAction)) {
// App launched via package name
} else {
// App was launched via Click on App Icon, or other means
normalLaunch();
}
}
_
私はnormalLaunch()
を想定しています。Intentのパラメーターを使用すべきではありません。そうでない場合は、デフォルトの起動方法を分離して最適化し、Intentパラメーターを使用しないようにする必要があります。
インテントのクリアオブジェクト:
intent.replaceExtras(new Bundle());
intent.setAction("");
intent.setData(null);
intent.setFlags(0);
短い答えはNo wayです
長い答え。 「ワンショット」インテントのようなものはありません。実験から、最近のAndroidでの最近の活動履歴は「意図の履歴」に過ぎないことが観察されています。アクティビティに渡された最新のインテントは単にシステムにログインされ、それが取引です。上記の人々は使用することを提案します
setAction("")
しかし、onNewIntent()またはonStart()メソッド内でインテントを取得する瞬間までインテントはすでにログに記録されているため、機能しません。
インテントの使用を避けることで問題を解決しました。私の問題は、著者によって投稿された問題に似ていました。通知領域のコントロールを介してアプリケーションからグローバル出口を実装しようとしました。基礎となるサービスを停止し、アプリのすべてのアクティビティを閉じる必要があります。 Wazeアプリケーションでも同じ動作を見つけることができます。
アルゴリズム:
インターネットで答えが見つからなかったので、これが誰かの助けになることを願っています。
PendingIntentにPendingIntent.FLAG_UPDATE_CURRENTフラグを使用していることを確認してください。
PendingIntent pendingIntent = PendingIntent.getActivity(this, 100, mPutIntent, PendingIntent.FLAG_UPDATE_CURRENT);
ここで、mPutIntent
はIntent
です。
これがお役に立てば幸いです。
Intent Extraを削除する方法が見つかりませんでした。 intentから余分なものを削除することについての答えは、を有効にすると機能しません(Do Not Keep Activities "開発者オプションから(これにより、アクティビティを破棄して、エクストラがまだ存在するかどうかをテストすることができます)。
問題に対する解決策として、Intent Extrasの処理後、ブール値をSharedPreferencesに保存しました。同じインテントがアクティビティに再配信されると、SharedPreferenceの値を確認し、Intent Extraを処理することにします。別の新しいIntent Extraを同じアクティビティに送信する場合、SharedPreferenceの値をfalseにするとアクティビティが処理します。 例:
// Start Activity with Intent Extras
Intent intent = new Intent(context, MyActivity.class);
intent.putExtra("someData", "my Data");
// Set data as not processed
context.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE).edit().putBoolean("myActivityExtraProccessed", false).commit();
context.startActivity(intent);
...
public class MyActivity{
...
public void someMethod(){
boolean isExtrasProcessed = context.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE).getBoolean("myActivityExtraProccessed", false);
if (!isExtrasProcessed) {
// Use Extras
//Set data as processed
context.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE).edit().putBoolean("myActivityExtraProccessed", true).commit();
}
}
}
私はまったく同じ問題を抱えています。私の解決策は、boolean
が「使用」されたときに設定されたIntent
変数と、このif
に基づくboolean
ステートメントを追加して、Intent
かどうか。
私は最近この問題を抱えていたので、意図に追加パラメーターとしてタイムスタンプを追加することで解決しました。
private void launchActivity(Context context) {
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("KEY_EXTRA_TIMESTAMP", System.currentTimeMillis());
context.startActivity(intent);
}
その後、タイムスタンプを共有設定に保存します。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
long time = getIntent().getLongExtra("KEY_EXTRA_TIMESTAMP", -1);
long previousTime = getPreferences(MODE_PRIVATE).getLong("timestamp", -1);
//ignore if the timestamp is the same as the previous one
if (time != previousTime) {
handleIntent(getIntent());
if (time != -1) {
//save the timestamp
getPreferences(MODE_PRIVATE).edit().putLong("timestamp", time).apply();
}
}
}
インテントの処理が完了したら、次の操作を行います。
setIntent(null);
処理されたインテントが再び表示されることはなく、処理されたインテントの内容を編集して問題を隠蔽することもありません。
解析後にIntentおよびIntentエクストラを手動でクリアした後でも、Activity.getIntent()は常にActivityを開始した元のIntentを返すようです。
これを回避するには、次のようなものをお勧めします。
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// The Intent provided by getIntent() (and its extras) will persist through a restore
// via savedInstance. Because of this, restoring this activity from a
// an instance that was originally started with extras (deep-link or
// pre-defined destination) may cause un-desired behavior
// (ie...infinite loop of sending the user directly to somewhere else because of a
// pre-defined alternate destination in the Intent's extras).
//
// To get around this, if restoring from savedInstanceState, we explicitly
// set a new Intent *** to override the original Intent that started the activity.***
// Note...it is still possible to re-use the original Intent values...simply
// set them in the savedInstanceState Bundle in onSavedInstanceState.
if (savedInstanceState != null) {
// Place savedInstanceState Bundle as the Intent "extras"
setIntent(new Intent().putExtras(savedInstanceState));
}
processIntent(getIntent())
}
private void processIntent(Intent intent) {
if (getIntent().getExtras() == null) {
// Protection condition
return;
}
doSomething(intent.getExtras.getString("SOMETHING_I_REALLY_NEED_TO_PERSIST"));
final String somethingIDontWantToPersist =
intent.getExtras.getString("SOMETHING_I_DONT_WANT_TO_PERSIST");
if(somethingIDontWantToPersist != null) {
doSomething(somethingIDontWantToPersist);
}
}
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save selective extras from original Intent...
savedInstanceState.putString("SOMETHING_I_REALLY_NEED_TO_PERSIST", "persistedValued");
super.onSaveInstanceState(savedInstanceState);
}
このように、元のインテント/インテントエクストラの特定の部分を明示的に保持する機能を保持しながら、元のインテントをダンプするメカニズムがあります。
すべてのアクティビティ起動モードをテストしたわけではないことに注意してください。
簡単な方法は、onCreate()以外のメソッドからgetIntent()を呼び出さないようにすることです。ただし、ユーザーが[ホーム]ボタンをタップしてアクティビティを終了すると、次回の起動時に問題が発生します。この問題には完全に機能する解決策がないと思います。
同じ問題に直面し、上記の方法を使用しようとしましたが、機能しません。
SingleTopモードを使用したacitvityの起動モードの原因であると思われます。
アプリをバックグラウンドで使用し、RamEaterを使用して、nullを設定したりキーを削除したりしてもインテントに常に余分な問題があることをシミュレートする場合。
この問題は、Androidの設定ストレージを使用して、パススルーしたことを確認することで解消されました。