Как возобновить намерение уведомления, а не новое?
У меня есть простое веб-представление, которое при загрузке автоматически отображает текущее уведомление. Идея состоит в том, что люди могут отойти от этой деятельности и снова быстро получить к ней доступ с любого экрана, выполнив выпадающее меню и выбрав его. Затем, когда они хотят, они могут просто закрыть уведомление, нажав кнопку меню и нажав выход, а затем уведомление очищается. Это все отлично работает. Однако при нажатии уведомления запускается новый экземпляр действия. Что мне нужно изменить, чтобы увидеть, если действие еще не уничтожено, и я могу просто вызвать этот экземпляр обратно (возобновить его) и, следовательно, не нужно загружать его снова и не нужно будет добавлять другое действие в мой стек, Есть идеи? Любая помощь будет принята с благодарностью.
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
Просто чтобы убедиться, что я правильно понял, это то, что вы предлагали?
Я был немного обеспокоен этой линией,
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...");
}
5 ответов
Идея состоит в том, что люди могут отойти от этой деятельности и снова быстро получить к ней доступ с любого экрана, выполнив выпадающее меню и выбрав его.
Пожалуйста, сделайте это необязательным.
Однако при нажатии уведомления запускается новый экземпляр действия.
Это произойдет по умолчанию.
Что мне нужно изменить, чтобы увидеть, если действие еще не уничтожено, и я могу просто вызвать этот экземпляр обратно (возобновить его) и, следовательно, не нужно загружать его снова и не нужно будет добавлять другое действие в мой стек,
Избавляться от FLAG_ACTIVITY_NEW_TASK
, добавлять notifyIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
- см. этот пример проекта.
Context context = getApplicationContext();
Пожалуйста, не делай этого. Просто используйте свой Activity
как Context
,
Это мой способ показывать уведомления. Я надеюсь, что это поможет вам.
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());
}
На всякий случай, если у кого-то есть такая же сложность, как у меня
Я попробовал весь приведенный выше код безуспешно - элемент уведомления продолжал запускать совершенно новый экземпляр моего приложения, даже если оно уже запущено. (Я хочу, чтобы в любой момент времени был доступен только один экземпляр.) Наконец, заметил этот другой поток ( /questions/37878429/android-ne-povtorno-ispolzuet-osnovnoe-dejstvie-i-zapuskaet-neskolko-ekzemplyarov-povedenie-tolko-posle-ispolzovaniya-pendingintent/37878434#37878434), у которого была одна простая дополнительная запись, необходимая в манифесте:
android:launchMode="singleInstance"
Я поместил это в манифест под разделом основной активности моего приложения, а затем элемент уведомления повторно использовал уже запущенный экземпляр.
Ни одно из решений не сработало для меня, поэтому я нашел свой путь. Все мои действия расширены с BaseActivity
, Я выполнил простую серию шагов, чтобы заставить мое push-уведомление нажать кнопку возобновить приложение:
Шаг 1: Постоянная запись текущей активности:
public static Context currentContext;
Шаг 2: в onCreate()
или же onResume()
деятельности продлен BaseActivity
currentContext = this;
Шаг 3: Intent
при создании уведомления:
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);
Я обнаружил, что ни один из ответов не работал для многозадачного приложения. По понятным причинам Intent.FLAG_ACTIVITY_CLEAR_TOP и Intent.FLAG_ACTIVITY_SINGLE_TOP ведут себя не одинаково в случае нескольких задач. В моем приложении есть несколько действий с корнем задачи. В какой-то момент пользователю будет показано уведомление о том, что необходимо выполнить работу по одной из этих задач. В отличие от ОП, мне нужно только вернуться к началу одной из этих задач, а не к конкретной деятельности, которая может быть похоронена в одной из этих задач. Я думаю, что это достаточно похоже на заданный вопрос, что может быть полезным для кого-то еще.
Мое решение состоит из статического идентификатора задачи для отслеживания текущей задачи, широковещательного приемника для обработки ожидающих намерений, нового тега разрешения использования и некоторого простого использования 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"/>
По сути, идея заключается в том, что вы отмечаете результат вызова Activity.getTaskId() в состояние. Позже, когда вы создаете уведомление, чтобы возобновить выполнение задачи, захватите идентификатор задачи и добавьте его в дополнительное. Затем установите ожидающее намерение указать на широковещательный приемник, который извлекает идентификатор задачи и запускает эту задачу.
Похоже, для этого требуется API 21 с вызовами, которые я использовал, и я подозреваю, что могут потребоваться некоторые дополнительные проверки ошибок, если задача уже была завершена, но она служит моим целям.