web-dev-qa-db-fra.com

Comment faire reprendre l'intention de notification plutôt que de faire une nouvelle intention?

Ce que j'ai ici est une simple activité de visualisation Web qui, une fois chargée, affiche automatiquement une notification en cours. L'idée est que les gens puissent s'éloigner de cette activité et y accéder rapidement à nouveau à partir de n'importe quel écran de leur choix en déroulant le menu déroulant et en le sélectionnant. Ensuite, quand ils le souhaitent, ils peuvent simplement fermer la notification en appuyant sur le bouton de menu et en appuyant sur Quitter, puis la notification s'efface. Tout fonctionne bien. Cependant, lorsque vous appuyez sur la notification, une nouvelle instance de l'activité démarre. Que devrais-je changer pour lui faire voir si l'activité n'a pas déjà été détruite et je peux simplement rappeler cette instance (la reprendre) et donc ne pas avoir besoin de la recharger et je n'aurai pas besoin d'ajouter une autre activité à ma pile . Des idées? Toute aide serait grandement appréciée.

package com.my.app;

import com.flurry.Android.FlurryAgent;

import Android.app.Activity;
import Android.app.Notification;
import Android.app.NotificationManager;
import Android.app.PendingIntent;
import Android.app.ProgressDialog;
import Android.content.Context;
import Android.content.Intent;
import Android.os.Bundle;
import Android.util.Log;
import Android.view.KeyEvent; 
import Android.view.Menu;
import Android.view.MenuInflater;
import Android.view.MenuItem;
import Android.webkit.CookieSyncManager;
import Android.webkit.WebView;
import Android.webkit.WebViewClient;
import Android.widget.Toast;

public class Chat extends Activity { 
    private ProgressDialog progressBar;
    public WebView webview;
    private static final String TAG = "Main";

    private NotificationManager mNotificationManager;
    private int SIMPLE_NOTFICATION_ID;

    @Override
    public void onStart() {
       super.onStart();
       CookieSyncManager.getInstance().sync();
       FlurryAgent.onStartSession(this, "H9QGMRC46IPXB43GYWU1");
    }

    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.chat);

        mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

        final Notification notifyDetails = new Notification(R.drawable.chat_notification,"Chat Started",System.currentTimeMillis());

        notifyDetails.flags |= Notification.FLAG_ONGOING_EVENT;

        Context context = getApplicationContext();

        CharSequence contentTitle = "Chat";
        CharSequence contentText = "Press to return to chat";

        Intent notifyIntent = new Intent(context, Chat.class);

        PendingIntent intent =
        PendingIntent.getActivity(Chat.this, 0,
        notifyIntent, Android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
        notifyDetails.setLatestEventInfo(context, contentTitle, contentText, intent);

        mNotificationManager.notify(SIMPLE_NOTFICATION_ID, notifyDetails);

        CookieSyncManager.createInstance(this);
        CookieSyncManager.getInstance().startSync();
        webview = (WebView) findViewById(R.id.webviewchat);
        webview.setWebViewClient(new chatClient());
        webview.getSettings().setJavaScriptEnabled(true);
        webview.getSettings().setPluginsEnabled(true);
        webview.loadUrl("http://google.com");

        progressBar = ProgressDialog.show(Chat.this, "", "Loading Chat...");  
    }

    private class chatClient extends WebViewClient { 
        @Override 
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            Log.i(TAG, "Processing webview url click...");
            view.loadUrl(url);
            return true;
        }

        public void onPageFinished(WebView view, String url) {
            Log.i(TAG, "Finished loading URL: " +url);
            if (progressBar.isShowing()) {
                progressBar.dismiss();
            }
        }
    }

    public boolean onKeyDown(int keyCode, KeyEvent event) { 
        if ((keyCode == KeyEvent.KEYCODE_BACK) && webview.canGoBack()) { 
            webview.goBack(); 
            return true; 
        }
        return super.onKeyDown(keyCode, event); 
    }

    @Override
    public boolean onCreateOptionsMenu (Menu menu) {
        super.onCreateOptionsMenu(menu);
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.chatmenu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected (MenuItem item) {
        switch (item.getItemId()) {
            case R.id.home:
                Intent a = new Intent(this, Home.class);
                startActivity(a);
                return true;
            case R.id.closechat:
                mNotificationManager.cancel(SIMPLE_NOTFICATION_ID);
                Intent v = new Intent(this, Home.class);
                startActivity(v);
                return true;
        }
        return false;
    }

    public void onStop() {
       super.onStop();
       CookieSyncManager.getInstance().sync();
       FlurryAgent.onEndSession(this);
    }
}

@Commonsware

Juste pour être sûr d'avoir bien compris, est-ce ce que vous proposiez?

J'étais un peu inquiet pour cette ligne,

PendingIntent.getActivity(Chat.this, 0, notifyIntent, SIMPLE_NOTFICATION_ID);

public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.chat);

    mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

    final Notification notifyDetails = new Notification(R.drawable.chat_notification,"Chat Started",System.currentTimeMillis());

    notifyDetails.flags |= Notification.FLAG_ONGOING_EVENT;


    Context context = getApplicationContext();

    CharSequence contentTitle = "Chat";
    CharSequence contentText = "Press to return to chat";

    Intent notifyIntent = new Intent(context, Chat.class);

    PendingIntent intent =
    PendingIntent.getActivity(Chat.this, 0, notifyIntent, SIMPLE_NOTFICATION_ID);
    notifyDetails.setLatestEventInfo(context, contentTitle, contentText, intent);
    notifyIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

    mNotificationManager.notify(SIMPLE_NOTFICATION_ID, notifyDetails);


    CookieSyncManager.createInstance(this);
    CookieSyncManager.getInstance().startSync();
    webview = (WebView) findViewById(R.id.webviewchat);
    webview.setWebViewClient(new chatClient());
    webview.getSettings().setJavaScriptEnabled(true);
    webview.getSettings().setPluginsEnabled(true);
    webview.loadUrl("http://google.com");

    progressBar = ProgressDialog.show(Chat.this, "", "Loading Chat...");        
}
39
brybam

L'idée est que les gens puissent s'éloigner de cette activité et y accéder rapidement à nouveau à partir de n'importe quel écran de leur choix en déroulant le menu déroulant et en le sélectionnant.

Veuillez le rendre facultatif.

Cependant, lorsque vous appuyez sur la notification, une nouvelle instance de l'activité démarre.

Cela se produira par défaut.

Que devrais-je changer pour lui faire voir si l'activité n'a pas déjà été détruite et je peux simplement rappeler cette instance (la reprendre) et donc ne pas avoir besoin de la recharger et je n'aurai pas besoin d'ajouter une autre activité à ma pile .

Débarrassez-vous de FLAG_ACTIVITY_NEW_TASK. Ajoutez notifyIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); - voir cet exemple de projet .

Context context = getApplicationContext();

Veuillez ne pas faire ça. Utilisez simplement votre Activity comme Context.

55
CommonsWare

Ceci est ma méthode pour afficher les notifications. J'espère que ça t'aide.

private static void generateNotification(Context context, String message){
    Intent notificationIntent = new Intent(context, YOUR_ACTIVITY.class);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    PendingIntent intent = PendingIntent.getActivity(context, 0, notificationIntent, 0);

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
        .setSmallIcon(R.drawable.ic_launcher)
        .setContentTitle(context.getString(R.string.app_name))
        .setContentIntent(intent)
        .setPriority(PRIORITY_HIGH) //private static final PRIORITY_HIGH = 5;
        .setContentText(message)
        .setAutoCancel(true)
        .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS);
    NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(0, mBuilder.build());
}
21
Pedro Romão

Juste au cas où quelqu'un d'autre aurait la même difficulté que moi ...

J'ai essayé tout le code ci-dessus sans succès - l'élément de notification continuait de lancer une toute nouvelle instance de mon application même si une était déjà en cours d'exécution. (Je veux qu'une seule instance soit disponible à la fois.) Enfin, j'ai remarqué cet autre thread ( https://stackoverflow.com/a/20724199/4307281 ), qui avait une seule entrée supplémentaire nécessaire dans le manifeste:

Android:launchMode="singleInstance"

J'ai placé cela dans le manifeste sous la section d'activité principale de ma demande, puis l'élément de notification a réutilisé l'instance déjà en cours.

14
jkincali

Aucune des solutions n'a fonctionné pour moi, j'ai donc trouvé ma propre voie. Toutes mes activités sont étendues à partir d'un BaseActivity. J'ai suivi une simple série d'étapes pour que ma notification Push clique sur reprendre l'application:

Étape 1: Constante pour enregistrer l'activité actuelle:

public static Context currentContext;

Étape 2: dans onCreate() ou onResume() des activités étendues par BaseActivity

currentContext = this;

Étape 3: Intent lors de la création de la notification:

Class activity = BaseActivity.commonContext.getClass();
Intent intent = new Intent(this, activity);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

//FLAG_UPDATE_CURRENT is important
PendingIntent pendingIntent = PendingIntent.getActivity(this, (int)System.currentTimeMillis(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
1
TharakaNirmana

J'ai trouvé qu'aucune des réponses ne fonctionnait pour une application multitâche. Il semble que, naturellement, Intent.FLAG_ACTIVITY_CLEAR_TOP et Intent.FLAG_ACTIVITY_SINGLE_TOP ne se comportent pas exactement de la même manière dans le cas de tâches multiples. Dans mon application, il existe plusieurs activités de racine de tâche. À un moment donné, l'utilisateur recevra une notification indiquant qu'il y a du travail à faire dans l'une de ces tâches. Contrairement au PO, je n'ai qu'à retourner au sommet d'une de ces tâches, pas à une activité spécifique, qui peut être enterrée dans l'une de ces tâches. Je pense que cela est assez similaire à la question posée qu'il peut être utile à quelqu'un d'autre.

Ma solution consiste en un identifiant de tâche statique pour garder une trace de la tâche en cours, un récepteur de diffusion pour gérer les intentions en attente, une nouvelle balise d'autorisation d'utilisation et une utilisation simple de ActivityManager.

private static int taskID;

public static void setResumeTask(int tID)
{
    Log.e("TaskReturn", "Setting Task ID: " + tID);
    taskID = tID;
}

public static PendingIntent getResumeTask(Context appContext)
{
    return PendingIntent.getBroadcast(appContext, 0, new Intent(appContext, TaskReturn.class).putExtra(TaskReturn.EXTRA_TASK_ID, taskID), PendingIntent.FLAG_UPDATE_CURRENT);
}

public void onReceive(Context context, Intent intent)
{
    Log.e("TaskReturn", "Task Return!");
    if (intent.hasExtra(EXTRA_TASK_ID))
    {
        int taskToStart = intent.getIntExtra(EXTRA_TASK_ID, -1);
        Log.e("TaskReturn", "Returning To Task: " + taskToStart);
        ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.AppTask> allAppTasks = activityManager.getAppTasks();

        for (ActivityManager.AppTask task : allAppTasks)
        {
            Log.e("TaskReturn", "AllTasks: " + task.getTaskInfo().id + " " + task.getTaskInfo().affiliatedTaskId + " " + task.getTaskInfo().persistentId);
        }

        activityManager.moveTaskToFront(taskToStart, ActivityManager.MOVE_TASK_WITH_HOME);
    }
    else
    {
        Log.e("TaskReturn", "WHERE IS MY EXTRA!?!?!");
        //Boo...
    }
}

<uses-permission Android:name="Android.permission.REORDER_TASKS"/>

...

<receiver Android:name=".TaskReturn"/>

Fondamentalement, l'idée est que vous marquez le résultat d'un appel à Activity.getTaskId () à l'état. Plus tard, lors de la création d'une notification pour reprendre la tâche de cette activité, saisissez l'ID de tâche et jetez-le dans un supplément. Ensuite, définissez l'intention en attente pour pointer vers un récepteur de diffusion qui extrait l'ID de tâche et lance cette tâche.

Il semble que cela nécessite l'API 21 avec les appels que j'ai utilisés, et je pense qu'il pourrait avoir besoin de quelques vérifications d'erreurs supplémentaires si la tâche a déjà été arrêtée, mais cela sert mes objectifs.

1
dhakim