如何使通知意图恢复而不是制定新的意图?

时间:2010-07-22 01:14:18

标签: android android-activity android-intent notifications resume

我这里有一个简单的webview活动,加载后会自动显示正在进行的通知。我们的想法是,人们可以远离此活动,并通过下拉菜单并选择它,从他们想要的任何屏幕再次快速访问它。然后,当他们想要时,他们可以通过点击菜单按钮并点击退出关闭通知,然后清除通知。一切正常。但是,当按下通知时,它会启动活动的新实例。我需要更改什么才能看到活动是否尚未被销毁,我可以回调用该实例(恢复它),因此不需要再次加载它,也不需要在我的堆栈中添加其他活动。有任何想法吗?任何帮助将不胜感激。

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 个答案:

答案 0 :(得分:55)

  

这个想法是人们可以导航   远离这项活动而且很快   他们可以从任何屏幕再次访问它   希望通过下拉下拉   菜单并选择它。

请选择此选项。

  

但是,通知是   按下它开始一个新的实例   活动。

默认情况下会发生这种情况。

  

我需要做些什么来改变它   看活动还没有   被摧毁,我可以打电话   该实例返回(恢复它)和   因此无需再次加载   并且不需要添加其他活动   到我的堆栈。

摆脱FLAG_ACTIVITY_NEW_TASK。添加notifyIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); - 请参阅this sample project

Context context = getApplicationContext();

请不要这样做。只需将Activity用作Context

即可

答案 1 :(得分:21)

这是我显示通知的方法。我希望它对你有所帮助。

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

答案 2 :(得分:14)

以防其他人遇到同样的困难......

我尝试了上面的所有代码但没有成功 - 通知项目一直在启动我的应用程序的全新实例,即使其中一个已经在运行。 (我只想让一个实例在任何时候都可用。)最后注意到另一个线程(https://stackoverflow.com/a/20724199/4307281),它在清单中需要一个简单的附加条目:

android:launchMode="singleInstance"

我将它放在我的应用程序的主要活动部分下的清单中,然后通知项重用已经在进行中的实例。

答案 3 :(得分:1)

非解决方案对我有用,所以我找到了自己的方式。我的所有活动都来自BaseActivity。我按照一系列简单的步骤使我的推送通知点击恢复应用程序:

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

答案 4 :(得分:1)

我发现没有一个答案适用于多任务应用程序。似乎可以理解的是,在多个任务的情况下,Intent.FLAG_ACTIVITY_CLEAR_TOP和Intent.FLAG_ACTIVITY_SINGLE_TOP的行为并不完全相同。在我的应用程序中,有多个任务根活动。在某些时候,将向用户显示通知,即在其中一个任务中有工作要做。与OP不同,我只需要返回其中一个任务的顶部,而不是特定的活动,这些活动可能隐藏在其中一个任务中。我认为这与提出的问题类似,可能对其他人有用。

我的解决方案包括一个用于跟踪当前任务的静态任务ID,一个用于处理待处理意图的广播接收器,一个新的uses-permission标签,以及一些简单的ActivityManager使用。

std::vector<dog> dogs = get_dogs();
std::vector<std::string> dog_names;

dog_names.reserve(dogs.size());

std::transform(std::begin(dogs), std::end(dogs), std::back_inserter(dog_names), [](auto const& dog) { return dog.name(); });
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"/>

基本上,我们的想法是将对Activity.getTaskId()的调用结果标记为状态。稍后,在创建恢复到该活动任务的通知时,抓取任务ID并将其投入额外的任务ID。然后,将待定意图设置为指向拉出任务ID并启动该任务的广播接收器。

看起来这需要API 21和我使用的调用,我怀疑它可能需要一些额外的错误检查,如果任务已经退出,但它符合我的目的。