如何让Android服务与Activity进行通信

我正在编写我的第一个Android应用程序,并试图让我的头在服务和活动之间的沟通。 我有一个服务,将在后台运行,并做一些全球定位系统和基于时间的日志logging。 我将有一个将用于启动和停止服务的活动。

所以首先,我需要能够确定活动开始时服务是否正在运行。 这里还有一些其他的问题,所以我想我可以弄清楚(但随时提供build议)。

我真正的问题:如果活动正在运行,并开始服务,我需要一种方法让服务发送消息到活动。 简单的string和整数在这一点上 – 主要是状态消息。 这些消息不会定期发生,所以我不认为投票服务是一个好方法,如果有另一种方式。 当用户启动活动时,我只想要这种通信 – 我不想从服务启动活动。 换句话说,如果您启动了“活动”并且“服务”正在运行,那么在发生有趣的事情时,您将在“活动”界面中看到一些状态消息。 如果你没有启动活动,你将不会看到这些消息(他们不是很有趣)。

看来我应该能够确定服务是否正在运行,如果是的话,添加活动作为一个监听器。 然后在Activity暂停或停止时将Activity作为侦听器移除。 这实际上是可能的吗? 我唯一能想出来的方法就是让Activity实现Parcelable并创build一个AIDL文件,这样我就可以通过Service的远程接口传递它。 这似乎是矫枉过正,但我​​不知道如何执行writeToParcel()/ readFromParcel()。

有一个更容易或更好的方法? 感谢您的帮助。

编辑:

对于稍后对此感兴趣的任何人,都可以通过示例目录中的AIDL处理来自Google的示例代码:/apis/app/RemoteService.java

有三种明显的与服务沟通的方式:

  1. 使用意图
  2. 使用AIDL
  3. 使用服务对象本身(作为单例)

在你的情况,我会select3.做一个静态的引用自己的服务,并在onCreate()中填充它:

void onCreate(Intent i) { sInstance = this; } 

创build一个静态函数MyService getInstance() ,它返回静态sInstance

然后在Activity.onCreate()启动服务,asynchronous等待,直到服务实际启动(你可以让你的服务通过向活动发送一个意图来通知你的应用程序),并获取它的实例。 当你有这个实例时,注册你的服务监听器对象给你服务,并且你被设置了。 注意:当在Activity里面编辑Views时,你应该在UI线程中修改它们,这个服务可能会运行它自己的Thread,所以你需要调用Activity.runOnUiThread()

你需要做的最后一件事是在Activity.onPause()删除对你的监听器对象的引用,否则你的活动上下文的一个实例会泄漏,不好。

注意:只有当您的应用程序/活动/任务是唯一可以访问您的服务的进程时,此方法才有用。 如果不是这种情况,则必须使用选项1或2。

提问者可能早已经过去了,但如果有人search这个…

还有另一种方法来处理这个问题,我认为这可能是最简单的。

将BroadcastReceiver添加到您的活动。 注册它以在onResume中接收一些自定义意图并在onPause中取消注册。 然后当你想发送你的状态更新或你有什么时,从你的服务发送意图。

如果其他应用程序倾听了您的意图(任何人都可以做任何恶意的事情),请确保您不会不高兴,但除此之外,您应该没问题。

代码示例请求:

在我的服务中,我有:

 // Do stuff that alters the content of my local SQLite Database sendBroadcast(new Intent(RefreshTask.REFRESH_DATA_INTENT)); 

(RefreshTask.REFRESH_DATA_INTENT只是一个常量string。)

在我的收听活动中,我定义了我的BroadcastReceiver:

 private class DataUpdateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(RefreshTask.REFRESH_DATA_INTENT)) { // Do stuff - maybe update my view based on the changed DB contents } } } 

我在课堂顶部宣布我的接收器:

 private DataUpdateReceiver dataUpdateReceiver; 

我重写onResume来添加:

 if (dataUpdateReceiver == null) dataUpdateReceiver = new DataUpdateReceiver(); IntentFilter intentFilter = new IntentFilter(RefreshTask.REFRESH_DATA_INTENT); registerReceiver(dataUpdateReceiver, intentFilter); 

而我重写onPause添加:

 if (dataUpdateReceiver != null) unregisterReceiver(dataUpdateReceiver); 

现在我的活动正在倾听我的服务,说“嘿,去更新自己”。 我可以在Intent中传递数据,而不是更新数据库表,然后再回到find我的活动中的变化,但是由于我希望变化持续存在,所以通过db传递数据是有意义的。

使用LocalBroadcastManager来注册一个接收器来监听从您的应用程序中的本地服务发送的广播,参考这里:

http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html

使用Messenger是在服务和活动之间进行通信的另一种简单方法。

在活动中,使用相应的Messenger创build一个Handler。 这将处理来自您的服务的消息。

 class ResponseHandler extends Handler { @Override public void handleMessage(Message message) { Toast.makeText(this, "message from service", Toast.LENGTH_SHORT).show(); } } Messenger messenger = new Messenger(new ResponseHandler()); 

Messenger可以通过附加到消息来传递给服务:

 Message message = Message.obtain(null, MyService.ADD_RESPONSE_HANDLER); message.replyTo = messenger; try { myService.send(message); catch (RemoteException e) { e.printStackTrace(); } 

完整的示例可以在API演示中find: MessengerService和MessengerServiceActivity 。 请参阅完整示例了解MyService的工作方式。

我很惊讶没有人提及Otto事件总线库

http://square.github.io/otto/

我一直在我的android应用程序中使用它,它可以无缝工作。

其他注释中未提及的另一种方法是使用bindService()从活动绑定到服务,并在ServiceConnectioncallback中获取服务的实例。 如此处所述http://developer.android.com/guide/components/bound-services.html

另一种方式可能是通过活动和服务使用观察者与假模型类,实现MVC模式变化。 我不知道这是否是实现这一目标的最好方法,但这是对我有用的方法。 如果你需要一些例子请求它,我会张贴一些东西。

用代码示例跟进@MrSnowflake答案。 这是XABBER现在的开源Application类 。 Application类正在集中和协调Listeners和ManagerInterfaces等。 各种pipe理器都是dynamic加载的。 在Xabber中开始的活动将报告他们是什么types的Listener 。 当一个Service启动时,它就像启动一样报告给Application类。 现在要发送消息给Activity所有你需要做的就是让你的Activity成为你所需要的types的一个listener 。 在OnStart() OnPause()注册/取消注册。 Service可以要求Application类只是需要与之通话的listener ,如果它在那里,那么活动就准备好接收。

通过Application类,你会看到有更多的掠夺,然后这个。