Clic de notification: activité déjà ouverte

164

J'ai une application avec des notifications qui ouvrent une certaine activité si je clique dessus. Je veux que, si je clique sur la notification et que l'activité est déjà ouverte, elle n'est pas redémarrée, mais juste mise au premier plan.

Je pensais que je pourrais le faire avec le drapeau FLAG_ACTIVITY_BROUGHT_TO_FRONTou FLAG_ACTIVITY_REORDER_TO_FRONT, mais il continue de l'ouvrir à nouveau donc j'ai l'activité deux fois.

Voici mon code:

event_notification = new Notification(R.drawable.icon,
            mContext.getString(R.string.event_notif_message), System.currentTimeMillis()); 
Intent notificationIntent = new Intent(mContext, EventListActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
sendNotification(event_notification, notificationIntent, mContext.getString(R.string.event_notif_title),
                body, Utils.PA_NOTIFICATIONS_ID);

Puis-je le gérer avec des indicateurs ou dois-je stocker une variable dans SharedPreferences pour vérifier si elle est ouverte ou non?

Merci!

Développeur PX
la source
1
J'utilise intent.setFlags (Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NO_HISTORY);
ashraful

Réponses:

298

Vous devez définir l' launchModeattribut du que Activityvous commencez singleTop. Cela entraînera la livraison d'intentions entrantes à l'instance existante plutôt que de démarrer une nouvelle instance alors qu'elle se Activitytrouve déjà en haut de la pile de la tâche.

Cela se fait dans le manifeste en ajoutant android:launchMode="singleTop"à l' <activity>élément. Pour accéder à la dernière intention (si vous êtes intéressé par des données qui peuvent avoir été transmises avec elle), remplacez onNewIntent()votre Activity.

Devunwired
la source
6
Je suis tombé sur de nombreuses réponses qui disaient définir le drapeau de l'intention de diverses choses. Cela n'a pas fonctionné. Est-ce parce que l'intention, quel que soit son indicateur, va à une activité nouvellement créée? Je demande parce que Devunwired a dit que l'attribut launchMode change là où les intentions sont livrées.
lululoo
5
La page de documentation est à developer.android.com/guide/topics/manifest/…
Mifeng
1
Je vois que si vous utilisez cette approche sur l'activité en cours de lancement à partir de l'écran d'accueil, chaque fois que vous lancerez l'application commencera par l'activité racine, détruisant toutes les activités qui étaient précédemment affichées en haut. Ce n'est certainement pas un comportement attendu pour un utilisateur qui place l'application en arrière-plan lors d'une activité différente et la rouvre.
Allemand
38

Essayez de définir les indicateurs à la Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOPplace.

D'après la documentation de FLAG_ACTIVITY_CLEAR_TOP (c'est moi qui souligne):

S'il est défini et que l'activité en cours de lancement est déjà en cours d'exécution dans la tâche actuelle, alors au lieu de lancer une nouvelle instance de cette activité, toutes les autres activités en plus seront fermées et cette intention sera livrée au (maintenant le haut) ancienne activité en tant que nouvelle intention.

Par exemple, considérons une tâche composée des activités: A, B, C, D.Si D appelle startActivity () avec une intention qui résout le composant de l'activité B, alors C et D seront terminés et B recevra l'intention donnée , ce qui fait que la pile est maintenant: A, B.

L'instance en cours d'exécution de l'activité B dans l'exemple ci-dessus recevra le nouvel intent que vous démarrez ici dans sa méthode onNewIntent (), ou sera elle-même terminée et redémarrée avec la nouvelle intention. S'il a déclaré que son mode de lancement est "multiple" (par défaut) et que vous n'avez pas défini FLAG_ACTIVITY_SINGLE_TOP dans la même intention, alors il sera terminé et recréé; pour tous les autres modes de lancement ou si FLAG_ACTIVITY_SINGLE_TOP est défini, cet Intent sera livré à onNewIntent () de l'instance actuelle.

menthe tranquille
la source
1
C'est ce dont j'avais besoin. Il suffit d' ajouter une description que nous devons ajouter ce drapeaux à l' intention: new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP).
Morteza Rastgoo
6

Utilisez onNewIntent()pour gérer les nouvelles données à partir de la notification, cliquez sur et actualisez l'activité.

Dans onNewIntentobtenir les nouvelles données du nouvel intent (qui a servi par la nouvelle notification) et les attraper, par exemple:

title = intent.getStringExtra("title")

dans onCreateprécédemment :)

Il actualisera l'activité actuelle avec de nouvelles données de notification.

Vous pouvez également suivre ce tutoriel.

Afjalur Rahman Rana
la source
3
Notification.Builder mBuilder =
            new Notification.Builder(this)
            .setSmallIcon(R.drawable.cmplayer)
            .setContentTitle("CoderoMusicPlayer")
            .setContentText("PLayer0!");

    Intent resultIntent = new Intent(this, 

    AndroidBuildingMusicPlayerActivity.class);
        resultIntent.setAction(Intent.ACTION_MAIN);
        resultIntent.addCategory(Intent.CATEGORY_LAUNCHER);

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                resultIntent, 0);

        mBuilder.setContentIntent(pendingIntent);
        NotificationManager mNotificationManager =
            (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        mNotificationManager.notify(1, mBuilder.build());

Copiez simplement le code et collez-le dans votre activité principale du lanceur.

Voici la réponse originale

Communauté
la source
0

Je pense que vous devriez ajouter une logique pour que cela fonctionne, peut-être que cela peut aider:

Par exemple, j'ai un écran de démarrage (lanceur et principal) de l'application:

public class SplashScreen extends AppCompatActivity {
    private final int TIME_OUT = 2000;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash_screen);

        // Suscribirse al tema Notificaciones
        FirebaseMessaging.getInstance().subscribeToTopic("NOTA");
        if (getIntent().getExtras() != null) {
            if (getIntent().getExtras().size()>1){
                Intent home_activity = new Intent(getApplicationContext(), Home.class);
                home_activity.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                if (getIntent().getExtras() != null) {
                    for (String key : getIntent().getExtras().keySet()) {
                        String value = "" + getIntent().getExtras().getString(key);
                        Log.d("TAG", key + "=" + value);
                        switch (key) {
                            case "url":
                                home_activity.putExtra("url", value);
                                break;
                        }
                    }
                }
                startActivity(home_activity);
                finish();

            }else{
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Intent home_activity = new Intent(getApplicationContext(), Home.class);
                            home_activity.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                            startActivity(home_activity);
                            finish();
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                }, TIME_OUT);
            }


        } else {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    try {
                        Intent home_activity = new Intent(getApplicationContext(), Home.class);
                        home_activity.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                        startActivity(home_activity);
                        finish();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }, TIME_OUT);
        }

    }

}

Et dans mon FirebaseService, j'ai effectué les opérations suivantes:

public class FCMessagingService extends FirebaseMessagingService {

    private final String TAG = "PUSH";
    private String body = "";
    private static String _url = "";
    private static int numMessage = 0;

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);

        String from = remoteMessage.getFrom();
        Log.d(TAG, "Mensaje recibido de: " + from);

        if (remoteMessage.getNotification() != null) {
            Log.d(TAG, "Notificación: " + remoteMessage.getNotification().getBody());

            if (remoteMessage.getData().size() > 0) {
                Log.d(TAG, "Data: " + remoteMessage.getData());
                try {
                    JSONObject data = new JSONObject(remoteMessage.getData());
                    String url = data.getString("url");
                    Log.d(TAG, "onMessageReceived: \n" + "Extra Information: " + url);
                    this._url = url;
                    Log.d("_URL",_url);
                    mostrarNotificacion(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody());
                    mensaje(url, remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody());
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }



    }


    private void mensaje(String url, String title, String body){
        boolean acti =  Util.comprobarActivityALaVista(getApplicationContext(), "com.dev.android.subagan.MainActivity");
        if(acti){

            Intent imain = new Intent(MainActivity.URL);

            imain.putExtra("key_url",url);
            imain.putExtra("key_title",title);
            imain.putExtra("key_body",body);

            LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(imain);

        }else{

            Intent ihome = new Intent(Home.URL);

            ihome.putExtra("key_url",url);
            ihome.putExtra("key_title",title);
            ihome.putExtra("key_body",body);
            LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(ihome);

        }

    }




    private void mostrarNotificacion(String title, String body) {

        final int NOTIFICATION_ID = 3000;

        Intent intent = new Intent(this, MainActivity.class);
        intent.putExtra("url",_url);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);


        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT  );



        Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle(title)
                .setContentText(body)
                .setAutoCancel(true)
                .setSound(soundUri)
                .setTicker(body)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0, notificationBuilder.build());

    }

}
Carlos Alberto Gonzalez
la source
0
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(this, new Random().nextInt(), intent, 0);
Manjunath
la source
4
Veuillez expliquer comment votre code aide à résoudre le problème mentionné dans la question. Cela peut ne pas être évident pour les autres lecteurs confrontés aux mêmes problèmes / problèmes similaires.
NOhs