可选择启动活动并使用来自 Android 服务的通知。仅在存在某个应用程序时启动或通知

Posted

技术标签:

【中文标题】可选择启动活动并使用来自 Android 服务的通知。仅在存在某个应用程序时启动或通知【英文标题】:Optionally starting activities and using notifications from services in Android. Only launch or notify if a certain app is present 【发布时间】:2012-02-04 10:33:07 【问题描述】:

我在自己的应用程序中重用了一项服务(它既是“绑定”服务又是“已启动”服务),因为它可以进行很多我感兴趣的有用数据采集。一切正常,但我注意到问题。这段代码抛出异常:

Intent dialogIntent = new Intent();
    dialogIntent.setClassName(service.getBaseContext(), "com.mycompany.receiver.ui.DialogActivity"); // names changed to protect the innocent
    dialogIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
    dialogIntent.putExtra("message", message);
    service.getApplicationContext().startActivity(dialogIntent);

异常警告“未知活动”和“您检查过清单”。现在,这不是由于我没有将活动放在清单中造成的。事实上,这里真的应该抛出一个异常,因为我的应用程序没有这个活动!这是为原始应用程序编写的活动。起初我没有注意到它,因为只有当收集的数据超出一定范围时才会触发此代码。 我可以更改服务代码,但服务和原始应用程序必须像以前一样继续工作。只是在我的应用程序中,我对为此特定消息弹出一个活动不是特别感兴趣(这对我来说并不重要)。 我确实考虑过这一点,我可以在所有东西上扔一个 try/catch 块。但这似乎有点骇人听闻。如果原始应用程序/服务对中出现其他问题,我想知道它。我想出了以下想法,我需要帮助来为我指明正确的方向。

    有没有办法让服务知道当前正在运行哪些应用程序? 或者可能目前处于前台? 或者当前绑定到服务怎么样?

我对 1-3 感兴趣(用于一般知识和解决此问题),但 2 可能是最有用的。毕竟,可能有多个应用程序绑定到该服务,并且我不确定是否仅仅因为这条消息而将原始应用程序带到我自己的前台。 最后...... 忘记我说的一切,然后 4. 你会怎么解决这个问题?

我在代码的其他地方也有类似的问题:

Intent toLaunch = new Intent();
    toLaunch.setClassName(context, "com.mycompany.receiver.ui.BankingActivity");

    toLaunch.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    PendingIntent intentBack = PendingIntent.getActivity(context, 0, toLaunch, PendingIntent.FLAG_CANCEL_CURRENT);

    notify.setLatestEventInfo(context, title, message, intentBack);
    notifier.notify(NOTIFY_1, notify);

这个不会抛出异常;它会发出一个通知,当我点击它时,就会启动原始应用程序。这实际上可能没问题,但同样,最好不要这样做(或者可能是一种妥协——让通知程序通知应用程序是否至少被绑定,但不一定在前台)。想法?

非常感谢, 戴夫

【问题讨论】:

我有点理解您的服务和活动位于两个不同的 android 应用程序中。对吗? 并且可能在您启动意图之前,您可以检查Intent 是否匹配。您可以这样做private boolean isCallable(Intent intent) List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); return list.size() > 0; 以了解是否可以调用您的意图。 【参考方案1】:

你会怎么解决这个问题?

你从来没有真正说过“这个”是什么。我猜“这个”是:

如果有我的前台活动,我如何让服务通知我的前台活动,否则引发Notification(或者可能什么都不做)?

对于那个“this”,使用有序广播。正如我写的in a blog post from a ways back,这是通知前台活动或提出Notification 的方法:

    定义一个操作字符串,当事件发生时您要转到活动或通知(例如,com.commonsware.java.packages.are.fun.EVENT)。

    在您的活动中动态注册BroadcastReceiever,并为上述操作字符串设置IntentFilter,并具有正优先级(过滤器的默认优先级为0)。然后,该接收器应该让 Activity 执行它需要执行的任何操作,以根据该事件更新 UI。接收方还应拨打abortBroadcast() 以防止其他人得到它。请务必在onStart()onResume() 中注册接收器,并在相应的onStop()onPause() 方法中取消注册接收器。

    在您的清单中注册一个BroadcastReceiver,并为上述操作字符串设置一个<intent-filter>。这个接收者应该提出Notification

    在您的服务中(例如,IntentService),当事件发生时,调用sendOrderedBroadcast()

如果您只是想通知您的某个前台活动,但如果它不在前台则不执行任何操作,请跳过第 3 步。

Here is a sample project 证明了这一点。

服务有没有办法知道当前正在运行哪些应用程序?

你可以问ActivityManager,但坦率地说,这是在问一个脆弱的应用程序。

或者可能目前在前台?

不可靠。

或者当前绑定到服务怎么样?

仅当您自己跟踪时。

【讨论】:

感谢您的快速回答。我会学习你的例子,买你的书!你说得对;我很啰嗦。让我简明扼要。我为您提供此服务,并说:“随意使用它,但如果您更改代码,它仍然需要与我的应用程序一起使用”。你会如何修改上面的代码?您的应用程序中没有“DialogActivity”,甚至没有我的应用程序。如果您不要求我更改我的应用程序(尽管不是必需的),那就太好了。您不想在手机上收到通知。你没有我的应用程序。您只想使用服务,而不是这些部分。 @Dave:即兴发挥,我会让服务在与startService() 一起使用的Intent 上附加一个PendingIntent,并让服务在何时调用PendingIntent无论您担心的是什么事件都会发生。如果PendingIntentnull,则服务会跳过它。任何想要出现Activity 的人都会提供getActivity() PendingIntent;任何想要Notification 的人(可能)都会提供一个getBroadcast() PendingIntent,该BroadcastReceiver 会引发Notification

以上是关于可选择启动活动并使用来自 Android 服务的通知。仅在存在某个应用程序时启动或通知的主要内容,如果未能解决你的问题,请参考以下文章

运行应用小部件 - 无法识别启动活动

Android:如何获取已安装活动的列表,就像它们出现在启动器中一样,没有重复

清除整个历史堆栈并在 Android 上启动一个新活动

每次应用程序来自android的后台时启动第一个屏幕

与来自服务的活动(LocalService)通信 - Android 最佳实践

Android:从可点击文本启动活动