Intento: se l'attività è in esecuzione, portala in primo piano, altrimenti avviane una nuova (dalla notifica)


129

La mia app ha delle notifiche, che - ovviamente - senza alcun flag, avviano ogni volta una nuova attività in modo da ottenere più stesse attività in esecuzione l'una sull'altra, il che è semplicemente sbagliato.

Quello che voglio che sia fare è portare in primo piano l'attività specificata nelle notifiche in attesa dell'intenzione, se è già in esecuzione, altrimenti avviarla.

Finora, l'intento / in attesa di quella notifica che ho è

private static PendingIntent prepareIntent(Context context) {
    Intent intent = new Intent(context, MainActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

    return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}

e stranamente, a volte funziona, a volte no ... Sento di aver già provato ogni singola combinazione di bandiere.

Risposte:


131

Puoi usare questo:

<activity 
   android:name=".YourActivity"
   android:launchMode="singleTask"/>

che funzionerà in modo simile "singleInstance"ma non avrà quella strana animazione.


15
+1, dovresti essere la risposta accettata. Le differenze sono qui: developer.android.com/guide/topics/manifest/…
user1032613

1
Per chiarire, usa singleTask se hai più attività nell'app e questo è il genitore, singleInstance se hai una sola attività.
gelido

4
Se qualcuno come me ha provato molte combinazioni di soluzioni prima di finire su questo sito: assicurati di sbarazzarti di altre modifiche che hai provato e assicurati di apportare questa modifica all'attività corretta. Mi ci è voluto troppo tempo per scoprire che questa soluzione avrebbe funzionato se non avessi provato anche altre soluzioni (ad esempio, l'override onNewIntente l'impostazione delle bandiere)
lucidbrot

Ho una mappa di Messenger, coppia di attività. Voglio visualizzare l'istanza Activity se ricevo un messaggio da essa. C'è un modo per farlo. ad esempio: HashMap.get (Messenger) .bringActivityToFront (); Voglio dire, l'attività è ancora in corso. Se apro un'attività recente e faccio clic su di essa, sarà onResume (); Cant I onResume () programmaticamente.

@JaveneCPPMcGowan che sembra una domanda completamente diversa, ti suggerisco di postare che, essendo la sua domanda, purtroppo non conosco davvero la risposta.
Franco,

46

Penso che il modo migliore per farlo e in modo semplice sia iniziare l'attività normalmente, ma impostare quell'attività nel manifest con la singleInstanceproprietà. In questo modo praticamente affronti entrambi i problemi che stai riscontrando in questo momento, portando l'attività sempre in primo piano e lasciando che il sistema operativo ne crei automaticamente uno nuovo se non esiste alcuna attività o porti in primo piano l'attività attualmente esistente (grazie al singleInstanceproprietà).

Questo è il modo in cui un'attività viene dichiarata come singola istanza:

<activity 
   android:name=".YourActivity"
   android:launchMode="singleInstance"/>

Inoltre, per evitare un'animazione instabile quando si avvia tramite singleInstance, è possibile utilizzare invece "singleTask", entrambi sono molto simili ma la differenza è spiegata qui come nella documentazione di Google:

<activity 
   android:name=".YourActivity"
   android:launchMode="singleTask"/>

singleInstance è uguale a "singleTask", tranne per il fatto che il sistema non avvia altre attività nell'attività che contiene l'istanza. L'attività è sempre il solo e unico membro del suo compito.

Spero che questo ti aiuti.

Saluti!


4
sembra funzionare, ma ora ogni altra nuova attività che lancio dal single Intent MainActivity, riproduce questa strana animazione ad arco invece della normale dissolvenza e scala
urSus

Che dire di lanciare una nuova attività ogni volta, ma cancellare tutte le altre istanze in esecuzione di essa, sarebbe possibile?
UrSus,

Beh, non penso che l'animazione che menzioni abbia qualcosa a che fare con la proprietà "singleInstance", tutto ciò che fa è riutilizzare l'istanza esistente, forse quell'animazione di cui stai parlando è un problema completamente diverso ...
Martin Cazares,

1
bene lo sto provando adesso e lo fa. Se rimuovo tutti i flag di intento e imposto il launchMode = "singleInstance" nel manifest, l'animazione bizzarra è lì, se la rimuovo, è tornata alla normalità
urSus

Sì, secondo la documentazione di Android, sembra che l'animazione "init" non sia più presente come al solito perché l'attività non viene inizializzata, viene semplicemente riutilizzata ...
Martin Cazares,

26

Penso che sia necessario ciò di cui hai bisogno singleTop Activity, piuttosto che un singleTasko singleInstance.

<activity android:name=".MyActivity"
          android:launchMode="singleTop"
          ...the rest... >

Ciò che la documentazione dice soddisfa perfettamente le tue esigenze:

[...] una nuova istanza di un'attività " singleTop" può anche essere creata per gestire un nuovo intento. Tuttavia, se l'attività di destinazione ha già un'istanza esistente dell'attività nella parte superiore del suo stack, quell'istanza riceverà il nuovo intento (in una onNewIntent()chiamata); non viene creata una nuova istanza. In altre circostanze, ad esempio, se un'istanza esistente dell'attività " singleTop" si trova nell'attività di destinazione, ma non nella parte superiore dello stack o se si trova nella parte superiore di uno stack, ma non nell'attività di destinazione, una nuova l'istanza verrebbe creata e inserita nello stack.

Oltre a ciò (nessun gioco di parole previsto), avevo esattamente lo stesso bisogno di te. Ho testato tutte le launchModebandiere per capire come si comportano effettivamente nella pratica e di conseguenza singleTopè effettivamente la migliore per questo: nessuna strana animazione, app visualizzata una volta nell'elenco delle applicazioni recenti (a differenza singleInstanceche la mostra due volte a causa del fatto che non lo fa ' permettere a chiunque altro Activitydi far parte del suo compito) e comportarsi in modo adeguato indipendentemente dal fatto che il bersaglio Activityesista o meno.


2
Lavoro fino alle 22:00 di venerdì sera e questo è quello che voglio ... Triste vita da sviluppatore.
felixwcf,

Ho risparmiato gran parte del mio tempo! Grazie!
hetsgandhi,

13

Questa è una vecchia discussione, ma per tutti coloro che stanno ancora cercando una risposta, ecco la mia soluzione. È puramente nel codice, senza impostazioni manifest:

private static PendingIntent prepareIntent(Context context) {
  Intent intent = new Intent(context, MainActivity.class);
  intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);      
  return PendingIntent.getActivity(context, NON_ZERO_REQUEST_CODE, intent, 
    PendingIntent.FLAG_UPDATE_CURRENT);
}

Qui FLAG_ACTIVITY_SINGLE_TOP apre l'attività esistente se si trova nella parte superiore dello stack di attività. Se non è in cima, ma all'interno dello stack, FLAG_ACTIVITY_CLEAR_TOP rimuoverà tutte le attività in cima all'attività di destinazione e la mostrerà. Se l'attività non è nello stack di attività, ne verrà creata una nuova. Un punto cruciale da menzionare: il secondo parametro di PendingIntent.getActivity (), ovvero requestCode dovrebbe avere un valore diverso da zero (l'ho anche chiamato NON_ZERO_REQUEST_CODE nel mio frammento), altrimenti quei flag di intenti non funzioneranno. Non ho idea del perché sia ​​così com'è. Flag FLAG_ACTIVITY_SINGLE_TOP è intercambiabile con android: launchMode = "singleTop" nel tag attività in manifest.


Combattere da ore con queste bandiere e mi chiedevo perché cambiando il mio intento le bandiere non cambiassero nulla. Codice di richiesta diverso da zero ... un punto cruciale da menzionare !!! Funziona ora! Grazie!
Max Power

9

So che è vecchio, ma nulla di quanto sopra si adattava alla mia applicazione.

Senza cambiare manifest e altre configurazioni, ecco il codice per riportare la tua app in primo piano o aprirla quando è chiusa

Intent notificationIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
notificationIntent.setPackage(null); // The golden row !!!
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

Questa è la vera risposta!
azizbekian

2
no, non funziona: aggiunge una nuova attività in aggiunta a quella corrente.
Tobliug,

3

Ho provato questo, e ha funzionato anche se l'IDE si lamentava del codice

Intent notificationIntent = new Intent(THIS_CONTEXT, MainActivity.class);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
    PendingIntent intent = PendingIntent.getActivity(THIS_CONTEXT, 0, notificationIntent, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(THIS_CONTEXT)
            .setSmallIcon(R.drawable.cast_ic_notification_0)
            .setContentTitle("Title")
            .setContentText("Content")
            .setContentIntent(intent)
            .setPriority(PRIORITY_HIGH) //private static final PRIORITY_HIGH = 5;
            .setAutoCancel(true)
            /*.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS)*/;
    NotificationManager mNotificationManager = (NotificationManager) THIS_CONTEXT.getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(0, mBuilder.build());

2
<attività android: name = ". MainActivity" android: launchMode = "singleTask">
nada

Intent.FLAG_ACTIVITY_REORDER_TO_FRONTnon è un flag valido perPendingINtent.getActivity
rds

@rds Puoi collegare la fonte?
Louis CAD

@LouisCAD Mi dispiace, non ho più accesso al codice sorgente
nada,

@rds Non sto chiedendo il codice sorgente, ma il link di dove leggi che Intent.FLAG_ACTIVITY_REORDER_TO_FRONTnon è un flag valido quando usato come PendingIntent. O forse volevi dire che non è valido per passare al getActivitymetodo, ma è valido da usare come Intentflag che viene quindi usato come PendingIntent?
Louis CAD

2

Dato che dici di voler iniziare la tua attività se non è già iniziata, forse non ti dispiacerebbe riavviarla. Ho testato un sacco di suggerimenti e combinazioni di flag anche per l'intento, questo porterà sempre in primo piano l'attività di cui hai bisogno, anche se non manterrà alcuno stato precedentemente associato ad esso.

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);

Solo API11 +.


0

Ho avuto un problema simile dopo aver aggiunto le notifiche che si trovano sul sito di formazione Android . Nessuna delle altre risposte qui ha funzionato per me, tuttavia questa risposta ha funzionato per me. Sommario:

final Intent notificationIntent = new Intent(context, YourActivity.class);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.