使用显式意图和隐式意图启动Android服务

10
根据标准的Android文档,启动一个服务(已经启动的服务)的首选方法是使用显式意图,如下所示:
// Using explicit intent:
Intent serviceIntent = new Intent(getApplicationContext(), MyService.class);
// or:
Intent serviceIntent = new Intent(this, MyService.class);
startService(serviceIntent);

你也可以使用在清单文件中指定的操作字符串通过隐式意图启动/停止服务,例如:

// Using implicit intent:
static final String serviceAction = "com.example.my.app.services.MYSERVICE";
Intent serviceIntent = new Intent(serviceAction);
startService(serviceIntent);

// AndroidManifest.xml:
<service android:name="com.example.my.app.services.MyService"
   android:exported="false" android:process=":services" >
   <intent-filter>
      <!-- Start/Stop service -->
      <action android:name="com.example.my.app.services.MYSERVICE" />
   </intent-filter>
</service>

当服务只在本地使用时(不允许第三方应用程序启动或绑定到它时),文档中建议在清单文件的服务标签中不包括intent-filter,并将exported标签设置为false。

注意:活动和服务在独立的进程(:application和:services进程)中运行。活动和服务之间的通信是通过实现AIDL接口来完成的(这是因为只有AIDL远程接口允许我在需要同时处理IPC的服务内进行多线程,主要是在:services进程中运行的服务之间,而不仅仅是活动之间)。

我的问题是:

Q1:当我在应用程序中使用的活动和服务在两个不同的进程中运行时,我需要使用隐式意图还是显式意图来启动和停止服务?

Q2:当:application进程消失(被销毁,在内存中不存在)且:services进程在后台运行时,如何从新的:application进程再次连接到已经运行的:services进程?我需要以某种方式再次获得对:services进程的引用,以便可以停止该进程内运行的正在运行的服务。据我所知,这不能使用AIDL完成。

问题在于Android可以轻松地销毁:application进程当资源不足时,这对我来说没问题,只要:services进程继续运行即可。(是的,我知道可以通过设置服务作为前台服务等方式来影响进程。我也能看懂手册;)但这不是我的问题)。

当活动和服务在分离的进程中并且使用AIDL时,并且:application进程需要在Android杀死它或用户再次进入应用程序后“找到”:services进程时,我找不到任何与我的问题相关的信息或答案。

欢迎任何专业级别的建议。


1
注意:活动和服务在单独的进程中运行(:应用程序和:服务进程)。请尽量避免这样做,因为它会使您的应用程序更加复杂,浪费内存、CPU/电池等资源。 - CommonsWare
@CommonsWare 感谢建议,我正在考虑。但是关于这些问题怎么办,它们还没有得到解决。 - user504342
2个回答

9
A1:即使您的活动和服务在不同的进程中运行,它们仍属于同一个应用程序。您仍然可以使用显式意图,我没有看到在这里使用隐式意图的特定优势(如果发现任何,请告诉我 :))。
A2:让我列举一些事实:
- “Started”服务(而不是“Bind”服务)的生命周期独立于启动此服务的活动的生命周期。无论两者是否在同一进程中运行,都是如此。 - 在任何时候只有一个服务实例处于活动状态。当您的活动调用startService()时,如果服务尚未运行,则会创建服务实例(在这种情况下,您的服务也将接收到onCreate()回调)。但是,如果服务已经在运行,则框架会简单地调用已经运行进程上的onStartCommand()回调(在这种情况下没有onCreate()回调)。同样,无论活动和服务是否在同一进程中运行,所有这些都是真实的。
现在来回答您的问题,如果您的服务仍在运行(由于之前的活动调用startService()),则bindService()/startService()将确保连接到现有服务。
希望这对您有所帮助。如果您有任何其他特定问题,请告诉我。

嗨,只是回答你的“如果发现任何问题,请告诉我”。当您使用隐式意图时,您正在使用服务的显式实现(或...实际上是接口)。这意味着您无法选择自己的实现(您应该更改代码来执行此操作)。 - Carlos Verdes

0

你不需要使用隐式意图来启动一个独立进程中的服务或活动;然而,使用独立进程来运行活动是一个罕见的场景。使用独立进程来运行服务更为常见,但无论如何,我想了解一下使用场景是什么。

如果你的应用进程被销毁然后重新启动,你可以使用startService来重新连接到服务。如果服务正在运行,你将会连接到它,否则服务将会重新启动。如果你想要终止服务,你可以终止它,或者从你的主应用程序运行stopService()。

这个服务在做什么?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接