题 如何从通知点击发送参数到活动?


我可以找到一种方法从我的通知中向我的活动发送参数。

我有一个创建通知的服务。当用户点击通知时,我想用一些特殊参数打开我的主要活动。例如,项目ID,因此我的活动可以加载并呈现特殊项目详细信息视图。更具体地说,我正在下载一个文件,当下载文件时,我希望通知有一个意图,当点击它时,它会以特殊模式打开我的活动。我试过用 putExtra 在我的意图,但似乎无法提取它,所以我认为我做错了。

来自我的服务的代码,用于创建通知:

        // construct the Notification object.
     final Notification notif = new Notification(R.drawable.icon, tickerText, System.currentTimeMillis());


    final RemoteViews contentView = new RemoteViews(context.getPackageName(), R.layout.custom_notification_layout);
    contentView.setImageViewResource(R.id.image, R.drawable.icon);
    contentView.setTextViewText(R.id.text, tickerText);
    contentView.setProgressBar(R.id.progress,100,0, false);
    notif.contentView = contentView;        

    Intent notificationIntent = new Intent(context, Main.class);
    notificationIntent.putExtra("item_id", "1001"); // <-- HERE I PUT THE EXTRA VALUE
    PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
    notif.contentIntent = contentIntent;

    nm.notify(id, notif);

我的Activity中的代码尝试从通知中获取额外参数:

 public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);


    Bundle extras = getIntent().getExtras();
    if(extras != null){
        Log.i( "dd","Extra:" + extras.getString("item_id") );
    }

额外的东西总是空的,我从来没有在我的日志中得到任何东西。

顺便说一下...... onCreate 仅在我的活动开始时运行,如果我的活动已经开始我还想收集额外的东西并根据我收到的item_id呈现我的活动。

有任何想法吗?


180
2017-07-29 07:29


起源




答案:


看看这个指南(创建通知)和样品ApiDemos“StatusBarNotifications”和“NotificationDisplay”。

要管理活动是否已经运行,您有两种方法:

  1. FLAG_ACTIVITY_SINGLE_TOP 在启动活动时向Intent标记,然后在活动类实现中 onNewIntent(意图意图) 事件处理程序,这样您就可以访问为活动调用的新意图(这与调用getIntent()不同,这将始终返回启动您的活动的第一个Intent。

  2. 与第一个相同,但不是向Intent添加标志,而是必须添加 “singleTop” 在您的活动AndroidManifest.xml中。

如果你使用意图额外,请记住打电话 PendingIntent.getActivity() 与国旗 PendingIntent.FLAG_UPDATE_CURRENT,否则将为每个通知重复使用相同的额外内容。


218
2017-07-29 15:50



并回答用户关于extras为null的问题:你必须打电话 PendingIntent.getActivity() 与国旗 PendingIntent.FLAG_UPDATE_CURRENT,否则将为每个通知重复使用相同的额外内容。 - Matthias
我只能使用列出的第二种方法来实现这一点。我在stackoverflow上看到其他地方,这可能是一个android bug。 - serenskye
我正在使用你的解决方案(Matthias评论,这是非常重要的,我决定将这么多的选票包括在你的答案中),我想问你是否可以看到任何问题使用 singleTask 活动标志而不是 singleTop。 - lorenzo-s
你节省了我的一天,但为什么要传输像android这样复杂的简单数据 - Illegal Argument
如果您应该有不同的通知,请确保在呼叫时使用不同的请求ID PendingIntent.getActivity() 除了设置 FLAG_ACTIVITY_SINGLE_TOP 在...上 Intent 和 FLAG_UPDATE_CURRENT 在...上 PendingIntent。看到 stackoverflow.com/questions/7370324/... - schnatterer


我有类似的问题,我的应用程序显示消息通知。 当有多个通知并单击每个通知时,它会在视图消息活动中显示该通知详细信息。我解决了在视图消息意图中收到相同额外参数的问题。

这是解决这个问题的代码。 用于创建通知Intent的代码。

 Intent notificationIntent = new Intent(getApplicationContext(), viewmessage.class);
    notificationIntent.putExtra("NotificationMessage", notificationMessage);
    notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingNotificationIntent = PendingIntent.getActivity(getApplicationContext(),notificationIndex,notificationIntent,PendingIntent.FLAG_UPDATE_CURRENT);
    notification.flags |= Notification.FLAG_AUTO_CANCEL;
    notification.setLatestEventInfo(getApplicationContext(), notificationTitle, notificationMessage, pendingNotificationIntent);

用于查看消息活动的代码。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    onNewIntent(getIntent());
}

@Override
public void onNewIntent(Intent intent){
    Bundle extras = intent.getExtras();
    if(extras != null){
        if(extras.containsKey("NotificationMessage"))
        {
            setContentView(R.layout.viewmain);
            // extract the extra-data in the Notification
            String msg = extras.getString("NotificationMessage");
            txtView = (TextView) findViewById(R.id.txtMessage);
            txtView.setText(msg);
        }
    }


}

85
2017-08-07 07:11



这样做对我来说,谢谢! - Piotrek Okoński
你为什么要自己打电话给NewIntent()? - katzenhut
据推测,所以txtView代码在onCreate中被调用。我认为有一个更整洁的解决方案,但是 - public void onNewIntent(Intent intent) { setIntent(intent); }  - 然后,在onCreate()中,你可以使用 Intent latestIntent = getIntent(); 获得最新的意图。 - ban-geoengineering
@katzenhut我在onCreate事件中调用了onNewIntent,因为在onCreate事件中没有触发onNewIntent事件,所以我必须手动调用它。第一次只触发onCreate事件。 - Muhammad Yousaf Sulahria
这里的请求代码有什么用?你不能得到它onCreate和一个待定的意图不会调用onActivityResult(..) - Roel


也许有点晚了,但是: 而不是这个:

public void onNewIntent(Intent intent){
    Bundle extras = intent.getExtras();
    Log.i( "dbg","onNewIntent");

    if(extras != null){
        Log.i( "dbg", "Extra6 bool: "+ extras.containsKey("net.dbg.android.fjol"));
        Log.i( "dbg", "Extra6 val : "+ extras.getString("net.dbg.android.fjol"));

    }
    mTabsController.setActiveTab(TabsController.TAB_DOWNLOADS);
}

用这个:

Bundle extras = getIntent().getExtras();
if(extras !=null) {
    String value = extras.getString("keyName");
}

24
2017-12-08 23:36



对于OP来说可能已经晚了,但对于互联网上的其他人来说,它永远不会迟到:) - espinchi
@pinaise谢谢老兄,它适合我:) - Akshay
或者更短:getIntent()。getStringExtra(“keyName”); - Juhani


在这里遇到同样的问题。 我通过使用不同的请求代码解决它,使用相同的ID作为通知,同时创建PendingIntent。但仍然不知道为什么要这样做。

PendingIntent contentIntent = PendingIntent.getActivity(context, **id**, notificationIntent, 0);
notif.contentIntent = contentIntent;
nm.notify(**id**, notif);

18
2018-01-26 13:57



这对我有用。它必须与一致的请求代码有关。遗憾的是,我在本文档中找不到相关内容。如果有人有解释,请发帖或评论。 developer.android.com/reference/android/app/PendingIntent.html - Nlinscott
适合我。我也想解释一下! - koherent
意味着两个id应该相同还是应该不同? - Dhrupal


在阅读了一些电子邮件列表和其他论坛之后,我发现这个技巧似乎将som唯一数据添加到意图中。

喜欢这个:

   Intent notificationIntent = new Intent(Main.this, Main.class);
   notificationIntent.putExtra("sport_id", "sport"+id);
   notificationIntent.putExtra("game_url", "gameURL"+id);

   notificationIntent.setData((Uri.parse("foobar://"+SystemClock.elapsedRealtime()))); 

我不明白为什么需要这样做,它与意图有关,只能通过它的附加物来识别......


13
2017-08-10 21:21



Anroid重用意图,意图动作和请求代码使其独特,但不是额外的数据。因此,您需要设置唯一的请求ID或使用不同的intent操作。 - Bachi
@Bachi我需要的只是改变了 requestID - Mehdi Khademloo
工作得很好:)(即使它是一个黑客)。 - Dimitar Vukman


我尝试了一切但没有任何效果。

最终提出了以下解决方案。

1- in manifest为活动添加             机器人:launchMode = “singleTop”

2-在进行挂起意图时执行以下操作,使用bundle而不是直接使用intent.putString()或intent.putInt()

                    Intent notificationIntent = new Intent(getApplicationContext(), CourseActivity.class);

                    Bundle bundle = new Bundle();
                    bundle.putString(Constants.EXAM_ID,String.valueOf(lectureDownloadStatus.getExamId()));
                    bundle.putInt(Constants.COURSE_ID,(int)lectureDownloadStatus.getCourseId());
                    bundle.putString(Constants.IMAGE_URL,lectureDownloadStatus.getImageUrl());

                    notificationIntent.putExtras(bundle);

                    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
                            Intent.FLAG_ACTIVITY_SINGLE_TOP);
                    PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(),
                            new Random().nextInt(), notificationIntent,
                            PendingIntent.FLAG_UPDATE_CURRENT); 

9
2018-04-01 12:56



这个对我有用。必须使用不同的requestCode值和PendingIntent.FLAG_UPDATE_CURRENT标志。 - phuongle
只有这个解决方案适合我 - mes
这应该是公认的答案 - Vivek Mishra
只有这个解决方案有效notificationIntent的标志是可选的。 - ZimaXXX
这对我来说就像一个魅力随机数和捆绑做了工作:) - Abhilash


AndroidManifest.xml中

包括launchMode =“singleTop”

<activity android:name=".MessagesDetailsActivity"
        android:launchMode="singleTop"
        android:excludeFromRecents="true"
        />

SMSReceiver.java

设置Intent和PendingIntent的标志

Intent intent = new Intent(context, MessagesDetailsActivity.class);
    intent.putExtra("smsMsg", smsObject.getMsg());
    intent.putExtra("smsAddress", smsObject.getAddress());
    intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);

    PendingIntent contentIntent = PendingIntent.getActivity(context, notification_id, intent, PendingIntent.FLAG_UPDATE_CURRENT);

MessageDetailsActivity.java

onResume() - 每次都被调用,加载额外的东西。

Intent intent = getIntent();
    String extraAddress = intent.getStringExtra("smsAddress");
    String extraBody = intent.getStringExtra("smsMsg");

希望它有所帮助,它基于stackoverflow上的其他答案,但这是最新的,对我有用。


2
2018-04-26 14:06





这很简单,这是我使用对象的解决方案!

我的POJO

public class Person implements Serializable{

    private String name;
    private int age;

    //get & set

}

方法通知

  Person person = new Person();
  person.setName("david hackro");
  person.setAge(10);

    Intent notificationIntent = new Intent(this, Person.class);
    notificationIntent.putExtra("person",person);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.notification_icon)
                .setAutoCancel(true)
                .setColor(getResources().getColor(R.color.ColorTipografiaAdeudos))
                .setPriority(2)
                .setLargeIcon(bm)
                .setTicker(fotomulta.getTitle())
                .setContentText(fotomulta.getMessage())
                .setContentIntent(PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT))
                .setWhen(System.currentTimeMillis())
                .setContentTitle(fotomulta.getTicketText())
                .setDefaults(Notification.DEFAULT_ALL);

新活动

 private Person person;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_notification_push);
    person = (Person) getIntent().getSerializableExtra("person");
}

祝你好运!!


2
2018-05-02 15:27





在做了一些搜索后,我从android开发者指南获得了解决方案

PendingIntent contentIntent ;
Intent intent = new Intent(this,TestActivity.class);
intent.putExtra("extra","Test");
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);

stackBuilder.addParentStack(ArticleDetailedActivity.class);

contentIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);

要在Test Activity类中获取Intent额外值,您需要编写以下代码:

 Intent intent = getIntent();
 String extra = intent.getStringExtra("extra") ;

1
2018-05-20 12:38



什么是 stackBuilder 对于? - AlexioVay


如果你使用

android:taskAffinity="myApp.widget.notify.activity"
android:excludeFromRecents="true"

在您的AndroidManifest.xml文件中,要启动Activity,您必须在意图中使用以下内容:

Intent notificationClick = new Intent(context, NotifyActivity.class);
    Bundle bdl = new Bundle();
    bdl.putSerializable(NotifyActivity.Bundle_myItem, myItem);
    notificationClick.putExtras(bdl);
    notificationClick.setData(Uri.parse(notificationClick.toUri(Intent.URI_INTENT_SCHEME) + myItem.getId()));
    notificationClick.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);  // schließt tasks der app und startet einen seperaten neuen

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
    stackBuilder.addParentStack(NotifyActivity.class);
    stackBuilder.addNextIntent(notificationClick);

    PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
    mBuilder.setContentIntent(notificationPendingIntent);

重要的是设置唯一数据,例如使用一个唯一的ID,如:

notificationClick.setData(Uri.parse(notificationClick.toUri(Intent.URI_INTENT_SCHEME) + myItem.getId()));

0
2017-10-13 08:12





用于服务 PendingIntent.FLAG_UPDATE_CURRENT

对我来说工作。


0
2018-03-23 16:33