Как уведомить о намерениях уведомления, а не делать новые намерения?

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

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

Ответ 1

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

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

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

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

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

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

Context context = getApplicationContext();

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

Ответ 2

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

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

Ответ 3

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

Я пробовал весь код выше без успеха - элемент уведомления продолжал запускать совершенно новый экземпляр моего приложения, хотя он уже был запущен. (Я хочу, чтобы один экземпляр был доступен в любой момент.) Наконец заметил этот другой поток (fooobar.com/questions/60437/...), в котором была одна простая дополнительная запись, необходимая в манифесте

android:launchMode="singleInstance"

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

Ответ 4

Не все решения работали для меня, поэтому я нашел свой собственный путь. Все мои действия продлеваются с 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);

Ответ 5

Я обнаружил, что ни один из ответов не работал для приложения с несколькими задачами. Похоже, что Intent.FLAG_ACTIVITY_CLEAR_TOP и Intent.FLAG_ACTIVITY_SINGLE_TOP не ведут себя точно так же в случае нескольких задач. В моем приложении есть несколько действий, связанных с задачами. В какой-то момент пользователю будет показано уведомление о том, что в одной из этих задач должна быть выполнена работа. В отличие от OP, мне нужно только вернуться к вершине одной из этих задач, а не к определенной деятельности, которая может быть похоронена в одной из этих задач. Я думаю, что это достаточно похоже на заданный вопрос, что он может быть полезен кому-то другому.

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