¿Cómo se puede reanudar el bash de notificación en lugar de hacer una nueva intención?

Lo que tengo aquí es una actividad de webview simple que cuando se carga automáticamente muestra una notificación en curso. La idea es que las personas puedan alejarse de esta actividad y acceder rápidamente a ella nuevamente desde cualquier pantalla que deseen, bajando el menú desplegable y seleccionándolo. Luego, cuando lo deseen, pueden cerrar la notificación presionando el botón de menú y presionando exit para luego despejar la notificación. Todo esto funciona bien Sin embargo, cuando se presiona la notificación, comienza una nueva instancia de la actividad. ¿Qué tendría que cambiar para que vea si la actividad aún no se ha destruido y puedo devolver esa instancia (reanudarla) y, por lo tanto, no necesitar cargarla nuevamente y no necesitar agregar otra actividad a mi stack? . ¿Algunas ideas? Cualquier ayuda sería muy apreciada.

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

Solo para estar seguro de que lo tengo correcto, ¿es esto lo que sugeriste?

Estaba un poco preocupado por esta línea,

 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..."); } 

La idea es que las personas puedan alejarse de esta actividad y acceder rápidamente a ella nuevamente desde cualquier pantalla que deseen, bajando el menú desplegable y seleccionándolo.

Por favor haz esto opcional.

Sin embargo, cuando se presiona la notificación, comienza una nueva instancia de la actividad.

Eso sucederá por defecto.

¿Qué tendría que cambiar para que vea si la actividad aún no se ha destruido y puedo devolver esa instancia (reanudarla) y, por lo tanto, no necesitar cargarla nuevamente y no necesitar agregar otra actividad a mi stack? .

Deshágase de FLAG_ACTIVITY_NEW_TASK . Agregar notifyIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); – ver este proyecto de muestra .

 Context context = getApplicationContext(); 

Por favor no hagas esto Solo usa tu Activity como Context .

Este es mi método para mostrar notificaciones. Espero que te ayude.

 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()); } 

Solo en caso de que alguien más tenga la misma dificultad que yo …

Probé todo el código anterior sin éxito: el elemento de notificación siguió lanzando una instancia completamente nueva de mi aplicación, aunque una ya se estaba ejecutando. (Solo quiero que una instancia esté disponible en cualquier momento). Finalmente noté este otro hilo ( https://stackoverflow.com/a/20724199/4307281 ), que tenía una entrada adicional simple necesaria en el manifiesto:

android:launchMode="singleInstance"

Coloqué eso en el manifiesto en la sección de actividad principal de mi aplicación y luego el elemento de notificación reutilizó la instancia que ya estaba en progreso.

Ninguna de las soluciones funcionó para mí, así que encontré mi propio camino. Todas mis actividades se extienden desde una BaseActivity . Seguí una simple serie de pasos para hacer que mi notificación de inserción haga clic en reanudar la aplicación:

Paso 1: Constante para registrar la actividad actual:

 public static Context currentContext; 

Paso 2: en onCreate() o onResume() de actividades extendidas por BaseActivity

 currentContext = this; 

Paso 3: Intent al crear la notificación:

 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); 

Descubrí que ninguna de las respuestas funcionaba para una aplicación de múltiples tareas. Parece que, comprensiblemente, Intent.FLAG_ACTIVITY_CLEAR_TOP y Intent.FLAG_ACTIVITY_SINGLE_TOP no se comportan exactamente igual en el caso de tareas múltiples. En mi aplicación, hay múltiples actividades de raíz de tareas. En algún momento, se le mostrará al usuario una notificación de que hay trabajo por hacer en una de estas tareas. A diferencia del OP, solo necesito volver a la parte superior de una de estas tareas, no a una actividad específica, que puede quedar oculta en una de estas tareas. Creo que esto es lo suficientemente similar a la pregunta formulada que puede ser útil para otra persona.

Mi solución consiste en una identificación de tarea estática para realizar un seguimiento de la tarea actual, un receptor de difusión para manejar bashs pendientes, una nueva etiqueta de permiso de uso y un uso simple del 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 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... } } 

  

  

Básicamente, la idea es marcar el resultado de una llamada a Activity.getTaskId () al estado. Más tarde, al crear una notificación para reanudar la tarea de esa actividad, tome la ID de la tarea y colóquela en un extra. Luego, establezca el bash pendiente de apuntar a un receptor de difusión que extraiga la identificación de la tarea y active esa tarea.

Parece que esto requiere API 21 con las llamadas que utilicé, y sospecho que podría necesitar algunas verificaciones de error adicionales si la tarea ya se ha cancelado, pero sirve para mis propósitos.