Как возобновить намерение уведомления, а не новое? - PullRequest
39 голосов
/ 22 июля 2010

У меня есть простое веб-представление, которое при загрузке автоматически отображает текущее уведомление. Идея состоит в том, что люди могут отойти от этого действия и быстро получить доступ к нему с любого экрана, который они хотят, выпадающий из выпадающего меню и выбрав его. Затем, когда они хотят, они могут просто закрыть уведомление, нажав кнопку меню и нажав выход, а затем уведомление очищается. Это все отлично работает. Однако при нажатии уведомления запускается новый экземпляр действия. Что бы мне пришлось изменить, чтобы увидеть, если действие еще не уничтожено, и я могу просто вызвать этот экземпляр обратно (возобновить его) и, следовательно, не нужно загружать его снова и не нужно будет добавлять другое действие в мой стек , Есть идеи? Любая помощь будет принята с благодарностью.

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 ]

55 голосов
/ 22 июля 2010

Идея в том, что люди могут ориентироваться от этой деятельности и быстро получить доступ к нему снова с любого экрана они хочу, потянув вниз выпадающего меню и его выбор.

Пожалуйста, сделайте это необязательным.

Однако, когда уведомление нажата начинает новый экземпляр деятельность.

Это произойдет по умолчанию.

Что бы мне пришлось изменить, чтобы сделать это посмотреть, если активность еще не был уничтожен, и я могу просто позвонить этот экземпляр обратно (возобновить его) и поэтому нет необходимости загружать его снова и не нужно будет добавлять другое действие в мою стопку.

Избавьтесь от FLAG_ACTIVITY_NEW_TASK. Добавьте notifyIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); - см. этот пример проекта .

Context context = getApplicationContext();

Пожалуйста, не делайте этого. Просто используйте ваш Activity как Context.

21 голосов
/ 15 мая 2013

Это мой способ показывать уведомления.Я надеюсь, что это поможет вам.

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());
}
14 голосов
/ 01 апреля 2015

На тот случай, если у кого-то еще возникнет такая же проблема, как и у меня ...

Я безуспешно перепробовал весь приведенный выше код - элемент уведомления продолжал запускать совершенно новый экземпляр моего приложения, хотя оно уже былоБег.(Я хочу, чтобы в любой момент времени был доступен только один экземпляр.) Наконец, заметил этот другой поток (https://stackoverflow.com/a/20724199/4307281),, у которого была одна простая дополнительная запись, необходимая в манифесте:

android:launchMode="singleInstance"

Я поместил это в манифест под раздел основной активности моего приложения, а затем элемент уведомления повторно использовал уже выполняющийся экземпляр.

1 голос
/ 15 марта 2017

Я обнаружил, что ни один из ответов не работает для многозадачного приложения. По понятным причинам 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 с вызовами, которые я использовал, и я подозреваю, что могут потребоваться дополнительные проверки ошибок, если задача уже была завершена, но она служит моим целям.

1 голос
/ 14 сентября 2016

Ни одно из решений не сработало для меня, поэтому я нашел свой путь. Все мои действия продлены с 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...