如何让Android服务与Activity进行通信
我正在编写我的第一个Android应用程序,并试图让我的头在服务和活动之间的沟通。 我有一个服务,将在后台运行,并做一些全球定位系统和基于时间的日志logging。 我将有一个将用于启动和停止服务的活动。
所以首先,我需要能够确定活动开始时服务是否正在运行。 这里还有一些其他的问题,所以我想我可以弄清楚(但随时提供build议)。
我真正的问题:如果活动正在运行,并开始服务,我需要一种方法让服务发送消息到活动。 简单的string和整数在这一点上 – 主要是状态消息。 这些消息不会定期发生,所以我不认为投票服务是一个好方法,如果有另一种方式。 当用户启动活动时,我只想要这种通信 – 我不想从服务启动活动。 换句话说,如果您启动了“活动”并且“服务”正在运行,那么在发生有趣的事情时,您将在“活动”界面中看到一些状态消息。 如果你没有启动活动,你将不会看到这些消息(他们不是很有趣)。
看来我应该能够确定服务是否正在运行,如果是的话,添加活动作为一个监听器。 然后在Activity暂停或停止时将Activity作为侦听器移除。 这实际上是可能的吗? 我唯一能想出来的方法就是让Activity实现Parcelable并创build一个AIDL文件,这样我就可以通过Service的远程接口传递它。 这似乎是矫枉过正,但我不知道如何执行writeToParcel()/ readFromParcel()。
有一个更容易或更好的方法? 感谢您的帮助。
编辑:
对于稍后对此感兴趣的任何人,都可以通过示例目录中的AIDL处理来自Google的示例代码:/apis/app/RemoteService.java
有三种明显的与服务沟通的方式:
- 使用意图
- 使用AIDL
- 使用服务对象本身(作为单例)
在你的情况,我会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的工作方式。
其他注释中未提及的另一种方法是使用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
类,你会看到有更多的掠夺,然后这个。