【问题标题】:How to make notification intent resume rather than making a new intent?如何使通知意图恢复而不是新的意图?
【发布时间】:2011-03-19 07:39:17
【问题描述】:

我这里有一个简单的 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...");        
}

【问题讨论】:

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


    【解决方案1】:

    这个想法是人们可以导航 远离这项活动并迅速 从他们的任何屏幕再次访问它 想要通过下拉下拉 菜单并选择它。

    请将此设为可选。

    但是,当通知 按下它会启动一个新实例 活动。

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

    我必须改变什么才能做到这一点 查看活动是否还没有 被摧毁了,我可以打电话 该实例返回(恢复它)和 因此不需要再次加载它 并且不需要添加其他活动 到我的堆栈。

    摆脱FLAG_ACTIVITY_NEW_TASK。添加notifyIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);——见this sample project

    Context context = getApplicationContext();
    

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

    【讨论】:

    • 非常感谢您看这个!当你有机会时,你介意看看上面的编辑吗?
    • 看看@commonsware 建议的示例项目,它帮助我很好地理解了它应该如何完成
    • 这对我也有用,但通知现在没有消失,有什么提示吗?
    • @MarthynOlthof: FLAG_AUTO_CLEAR Notification
    • 如何从通知中恢复当前任务的当前实例..我的共享应用程序有问题..当我通过图库应用程序共享照片时,它会打开我的共享活动..我使用创建了一个通知上面的代码,但不是恢复当前任务的当前实例,而是打开在我的应用程序任务堆栈中找到的实例(或者如果它不存在则创建一个新实例)
    【解决方案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】:

    以防万一其他人遇到与我相同的困难......

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

    android:launchMode="singleInstance"

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

    【讨论】:

    • 这对我有用。例如,如果您构建 GPS 活动,这将是正确的做法。
    • 这对我有用,是最简单的解决方案,也是最直接的。感谢分享。
    • 很好的解决方案,我在更改清单后找不到任何错误
    【解决方案4】:

    没有一个解决方案对我有用,所以我找到了自己的方法。我所有的活动都是从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);
    

    【讨论】:

      【解决方案5】:

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

      我的解决方案包括一个用于跟踪当前任务的静态任务 ID、一个用于处理未决意图的广播接收器、一个新的使用权限标签以及一些简单的 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() 的结果标记为状态。稍后,当创建通知以恢复该活动的任务时,获取任务 ID 并将其放入额外的。然后,将挂起的意图设置为指向一个广播接收器,该接收器提取任务 ID 并启动该任务。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-08-22
        • 1970-01-01
        • 2011-07-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-02
        相关资源
        最近更新 更多