Mon application Android est appelée par une intention qui transmet des informations (en attente dans la barre d'état).
Lorsque je clique sur le bouton d'accueil et que je rouvre mon application en maintenant le bouton d'accueil enfoncé, il rappelle l'intention et les mêmes extras sont toujours là.
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
c'est le code qui ne fonctionne pas comme si on le supposait
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
}
}
Et mon intention:
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);
}
Existe-t-il un moyen de clarifier l’intention ou de vérifier si elle a déjà été utilisée?
Je n'avais pas réalisé que cette réponse ferait tellement allusion lorsque je l'ai écrite pour la première fois il y a plus de 5 ans!
Je préciserai que, selon la réponse de @ tato-rodrigo, cela ne vous aidera pas à détecter une intention déjà gérée dans certaines situations.
Aussi, je devrais souligner que je mets "clair" entre guillemets pour une raison - vous êtes pas effacez vraiment l'intention en faisant cela, vous utilisez simplement la suppression de l'extra comme indicateur que cette intention a été vue par l'activité déjà.
J'ai eu exactement le même problème.
La réponse ci-dessus m'a mis sur la bonne voie et j'ai trouvé une solution encore plus simple, utilisez le:
getIntent().removeExtra("key");
appel de méthode pour "effacer" l'intention.
Il est un peu tardif depuis que cela a été demandé il y a un an, mais j'espère que cela aidera d'autres à l'avenir.
EDIT: J'édite pour publier la solution complète que j'utilise.
Cette solution fonctionnera si le problème est "Ne pas exécuter de code lorsque l'activité démarre à partir de l'historique (Applications récentes)".
Tout d’abord, déclarez une boolean
dans votre Activity
pour indiquer si la Intent
a déjà été consommée:
private boolean consumedIntent;
Ensuite, stockez et restaurez en toute sécurité cette valeur à l'aide des méthodes onSaveInstanceState
et onCreate
pour gérer les modifications de configuration et les cas où le système peut tuer votre Activity
lorsqu'elle passe en arrière-plan.
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
}
Maintenant, vérifiez si vous pouvez exécuter votre code avec la méthode 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
}
}
De plus, si votre Activity
est configuré sur singleTop
, vous devez réinitialiser votre indicateur lorsqu'un nouveau Intent
est remis.
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
consumedIntent = false;
}
Maks answer travaille pour dégager un extra:
getIntent().removeExtra("key");
Une autre commande utile est:
getIntent().setAction("");
Vous pouvez également marquer une intention en appelant:
getIntent().putExtra("used", true);
et puis juste pour vérifier la valeur.
Lorsque nous lançons des applications Android à partir de History (Recent Apps), l'application peut être lancée principalement avec trois indicateurs d'intention différents.
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY | FLAG_ACTIVITY_NEW_TASK
La valeur constante peut être récupérée via getIntent().getFlags()
Dans le troisième cas, Android recharge les dernières valeurs d’intention de sa mémoire. L'intention de votre application (getIntent
) aura donc les valeurs de la dernière intention qui a lancé l'application.
En fait, l'application devrait se comporter comme s'il s'agissait d'un nouveau lancement, avec les valeurs d'intention pour un nouveau lancement plutôt que les valeurs d'intention du lancement précédent. Ce comportement peut être observé si vous lancez l'application en cliquant sur l'icône de l'application, il n'aura jamais d'anciennes valeurs d'intention. En effet, Android utilise le filtre d'intention suivant pour ce scénario
<intent-filter>
<action Android:name="Android.intent.action.MAIN" />
<category Android:name="Android.intent.category.LAUNCHER"/>
</intent-filter>
Mais dans le troisième cas (application qui a été fermée, lancée à partir de l'historique des applications récentes), le système d'exploitation Android utilise la dernière intention qui a lancé l'application avant de la quitter (en appuyant sur le bouton Précédent). Donc, vous finissez par avoir d'anciennes valeurs d'intention et le flux d'application n'est pas correct.
Supprimer l’intention est un moyen de le résoudre, mais cela ne résoudrait pas complètement le problème! En tant que système d'exploitation Android recharge l'intention depuis le dernier lancement des applications, et non la dernière instance de l'intention de lancement.
Un moyen propre d'éviter ce problème consiste à le gérer en indiquant le type de Intention pour déterminer le type de lancement.
Ainsi, dans votre LaunchActivity (celui qui a le filtre d'intention défini dans le manifeste), vous pouvez utiliser le code suivant dans les méthodes onCreate()
, onStart()
ou 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();
}
}
Je suppose que normalLaunch()
, ne devrait pas utiliser les paramètres de l’intention; sinon, vous devrez séparer et optimiser votre méthode de lancement par défaut pour ne pas utiliser les paramètres d'intention.
intent.replaceExtras(new Bundle());
intent.setAction("");
intent.setData(null);
intent.setFlags(0);
La réponse courte est impossible
Longue réponse. Il n’existe pas d’intention «unique». Par expérience, on constate que l’histoire récente des activités d’Androïdes modernes n’est autre que «l’histoire de l’intention». La dernière intention transmise à l'activité est simplement connectée au système et c'est tout. Les gens ci-dessus suggèrent d'utiliser
setAction("")
Mais cela ne fonctionne pas parce que l'intention est déjà enregistrée jusqu'au moment où vous l'obtenez dans la méthode onNewIntent () ou onStart ().
J'ai résolu le problème en évitant l'utilisation d'intentions. Mon problème était semblable à celui posté par l'auteur. J'ai essayé d'implémenter Global Exit de l'application via le contrôle dans la zone de notification. Il devrait arrêter le service sous-jacent et fermer toutes les activités de l'application. Vous pouvez trouver le même comportement dans l'application Waze.
L'algorithme:
J'espère que cela aidera à quelqu'un parce que je n'ai pas trouvé la réponse sur Internet.
Assurez-vous que vous utilisez PendingIntent.FLAG_UPDATE_CURRENT flag pour PendingIntent .
PendingIntent pendingIntent = PendingIntent.getActivity(this, 100, mPutIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Où mPutIntent
est votre Intent
.
J'espère que ceci vous aidera.
Je ne pouvais pas trouver un moyen de supprimer Intent Extra . Aucune des réponses concernant supprimer les éléments supplémentaires de l'intention ne fonctionne si vous activez "Ne pas conserver les activités" dans Options du développeur (vous pouvez ainsi détruire Activité et revenir pour tester si des Extras existent toujours).
En tant que solution au problème, i stocke une valeur booléenne dans SharedPreferences après le traitement des suppléments Intent. Lorsque la même intention est redistribuée à l'activité, je vérifie la valeur SharedPreference et décide de traiter l'intention supplémentaire. Si vous envoyez une autre nouvelle Intent Extra à la même activité, vous définissez SharedPreference sur false et Activity la traite. Exemple :
// 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();
}
}
}
J'ai exactement le même problème. Ma solution consistait à ajouter la variable boolean
définie lorsque Intent
était 'utilisée' et l'instruction if
basée sur cette boolean
pour vérifier si vous deviez utiliser Intent
ou non.
J'ai récemment eu ce problème et je l'ai résolu en ajoutant un horodatage en tant que paramètre supplémentaire à l'intention:
private void launchActivity(Context context) {
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("KEY_EXTRA_TIMESTAMP", System.currentTimeMillis());
context.startActivity(intent);
}
Ensuite, enregistrez l’horodatage dans les préférences partagées:
@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();
}
}
}
Lorsque vous avez terminé de traiter l'intention, procédez comme suit:
setIntent(null);
Vous ne verrez plus cette intention traitée et vous ne masquerez pas le problème en modifiant le contenu de cette intention traitée.
Même après avoir effacé manuellement les extras d'intention et d'intention après leur analyse, il semble que Activity.getIntent () renvoie toujours l'intention d'origine qui a démarré l'activité.
Pour contourner cela, je recommande quelque chose comme ceci:
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);
}
De cette façon, il existe un mécanisme permettant de vider l’intention initiale tout en conservant la possibilité de conserver explicitement certaines parties des extras d’intention/intention originaux.
Notez que je n'ai pas testé tous les modes de lancement d'activité.
La méthode la plus simple consiste à éviter d'appeler getIntent () à partir de méthodes autres que onCreate (). Mais cela causera un problème lors du prochain lancement si l'utilisateur quitte notre activité en appuyant sur le bouton Accueil. Je pense que ce problème n'a pas une solution entièrement fonctionnelle.
Je suis confronté au même problème et j'essaie d'utiliser les méthodes ci-dessus, mais cela ne fonctionne pas.
Je pense que c'est peut-être à cause du mode de lancement de l'activité que j'ai utilisé le mode singleTop.
Lorsque j'appuie en arrière-plan et que j'utilise RamEater pour simuler le problème, cette intention a toujours un caractère supplémentaire, même si je la définis comme nulle ou si je supprime la clé.
Le problème a disparu en utilisant le stockage de préférences sur Android pour vérifier le passage.