如何让Android Service与Activity通信
我正在编写我的第一个 Android 应用程序,并试图了解服务和活动之间的通信。我有一个服务将在后台运行并执行一些 GPS 和基于时间的日志记录。我将有一个用于启动和停止服务的活动。
因此,首先,我需要能够确定活动启动时服务是否正在运行。这里还有一些其他问题,所以我想我可以解决这个问题(但请随意提供建议)。
我真正的问题:如果活动正在运行并且服务已启动,我需要一种方法让服务向活动发送消息。此时简单的字符串和整数 - 主要是状态消息。这些消息不会定期发生,因此如果有其他方法,我认为轮询服务不是一个好方法。我只希望在用户启动活动时进行此通信 - 我不想从服务启动活动。换句话说,如果您启动 Activity 并且 Service 正在运行,当发生有趣的事情时,您将在 Activity UI 中看到一些状态消息。如果您不启动活动,您将不会看到这些消息(它们没那么有趣)。
看来我应该能够确定服务是否正在运行,如果是,则将活动添加为侦听器。然后,当 Activity 暂停或停止时,将 Activity 作为侦听器移除。这实际上可能吗?我能想到的唯一方法是让 Activity 实现 Parcelable 并构建一个 AIDL 文件,以便我可以通过服务的远程接口传递它。但这似乎有点矫枉过正,我不知道 Activity 应该如何实现 writeToParcel() / readFromParcel()。
有没有更简单或更好的方法?感谢您的任何帮助。
编辑:
对于以后对此感兴趣的任何人,示例目录中有来自 Google 的示例代码,用于通过 AIDL 处理此问题:/apis/app/RemoteService.java
I'm writing my first Android application and trying to get my head around communication between services and activities. I have a Service that will run in the background and do some gps and time based logging. I will have an Activity that will be used to start and stop the Service.
So first, I need to be able to figure out if the Service is running when the Activity is started. There are some other questions here about that, so I think I can figure that out (but feel free to offer advice).
My real problem: if the Activity is running and the Service is started, I need a way for the Service to send messages to the Activity. Simple Strings and integers at this point - status messages mostly. The messages will not happen regularly, so I don't think polling the service is a good way to go if there is another way. I only want this communication when the Activity has been started by the user - I don't want to start the Activity from the Service. In other words, if you start the Activity and the Service is running, you will see some status messages in the Activity UI when something interesting happens. If you don't start the Activity, you will not see these messages (they're not that interesting).
It seems like I should be able to determine if the Service is running, and if so, add the Activity as a listener. Then remove the Activity as a listener when the Activity pauses or stops. Is that actually possible? The only way I can figure out to do it is to have the Activity implement Parcelable and build an AIDL file so I can pass it through the Service's remote interface. That seems like overkill though, and I have no idea how the Activity should implement writeToParcel() / readFromParcel().
Is there an easier or better way? Thanks for any help.
EDIT:
For anyone who's interested in this later on, there is sample code from Google for handling this via AIDL in the samples directory: /apis/app/RemoteService.java
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
提问者可能早已超越了这个,但万一其他人搜索这个......
还有另一种方法来处理这个问题,我认为这可能是最简单的。
将
BroadcastReceiver
添加到您的活动中。注册它以在onResume
中接收一些自定义意图,并在onPause
中取消注册它。然后,当您想要发送状态更新或您拥有的内容时,从您的服务中发送该意图。确保如果其他应用程序侦听您的
Intent
(有人会做任何恶意的事情吗?),您不会感到不高兴,但除此之外,您应该没问题。请求代码示例:
在我的服务中,我有这个:(
RefreshTask.REFRESH_DATA_INTENT
只是一个常量字符串。)在我的监听活动中,我定义了我的
BroadcastReceiver
:我声明我的接收器位于类的顶部:
我重写
onResume
来添加以下内容:我重写
onPause
来添加:现在我的活动正在监听我的服务说“嘿,你自己去更新吧。”我可以在
Intent
中传递数据,而不是更新数据库表,然后返回查找活动中的更改,但由于我希望更改始终保留,因此通过数据库传递数据是有意义的。The asker has probably long since moved past this, but in case someone else searches for this...
There's another way to handle this, which I think might be the simplest.
Add a
BroadcastReceiver
to your activity. Register it to receive some custom intent inonResume
and unregister it inonPause
. Then send out that intent from your service when you want to send out your status updates or what have you.Make sure you wouldn't be unhappy if some other app listened for your
Intent
(could anyone do anything malicious?), but beyond that, you should be alright.Code sample was requested:
In my service, I have this:
(
RefreshTask.REFRESH_DATA_INTENT
is just a constant string.)In my listening activity, I define my
BroadcastReceiver
:I declare my receiver at the top of the class:
I override
onResume
to add this:And I override
onPause
to add:Now my activity is listening for my service to say "Hey, go update yourself." I could pass data in the
Intent
instead of updating database tables and then going back to find the changes within my activity, but since I want the changes to persist anyway, it makes sense to pass the data via DB.与服务通信有三种明显的方法:
在您的情况下,我会选择选项 3。对服务本身进行静态引用并将其填充到 onCreate( ):
创建一个静态函数
MyService getInstance()
,它返回静态sInstance
。然后在 Activity.onCreate() 中启动服务,异步等待服务实际启动(您可以让您的服务通过向活动发送意图来通知您的应用程序已准备好。)并获取其实例。当您拥有实例时,将您的服务侦听器对象注册到您的服务,然后就完成了。注意:在 Activity 内编辑视图时,您应该在 UI 线程中修改它们,服务可能会运行自己的线程,因此您需要调用
Activity.runOnUiThread()
。您需要做的最后一件事是在
Activity.onPause()
中删除对侦听器对象的引用,否则 Activity 上下文的实例将泄漏,这不好。注意:仅当您的应用程序/活动/任务是访问您的服务的唯一进程时,此方法才有用。如果不是这种情况,您必须使用选项 1. 或 2。
There are three obvious ways to communicate with services:
In your case, I'd go with option 3. Make a static reference to the service it self and populate it in onCreate():
Make a static function
MyService getInstance()
, which returns the staticsInstance
.Then in
Activity.onCreate()
you start the service, asynchronously wait until the service is actually started (you could have your service notify your app it's ready by sending an intent to the activity.) and get its instance. When you have the instance, register your service listener object to you service and you are set. NOTE: when editing Views inside the Activity you should modify them in the UI thread, the service will probably run its own Thread, so you need to callActivity.runOnUiThread()
.The last thing you need to do is to remove the reference to you listener object in
Activity.onPause()
, otherwise an instance of your activity context will leak, not good.NOTE: This method is only useful when your application/Activity/task is the only process that will access your service. If this is not the case you have to use option 1. or 2.
使用
LocalBroadcastManager
注册一个接收器来监听应用程序内本地服务发送的广播,参考如下:http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html
Use
LocalBroadcastManager
to register a receiver to listen for a broadcast sent from local service inside your app, reference goes here:http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html
您还可以使用像
EventBus
一样工作的LiveData
。然后从您的
Activity
添加观察者。您可以从此博客阅读更多内容。
You may also use
LiveData
that works like anEventBus
.Then add an observer from your
Activity
.You can read more from this blog.
使用 Messenger 是在服务和活动之间进行通信的另一种简单方法。
在Activity中,创建一个Handler和对应的Messenger。这将处理来自您的服务的消息。
可以通过将 Messenger 附加到消息来将其传递给服务:
完整的示例可以在 API 演示中找到:MessengerService 和 MessengerServiceActivity。请参阅完整示例以了解 MyService 的工作原理。
Using a Messenger is another simple way to communicate between a Service and an Activity.
In the Activity, create a Handler with a corresponding Messenger. This will handle messages from your Service.
The Messenger can be passed to the service by attaching it to a Message:
A full example can be found in the API demos: MessengerService and MessengerServiceActivity. Refer to the full example for how MyService works.
我很惊讶没有人参考 Otto 事件总线库
http://square.github.io/otto/
我一直在我的 Android 应用程序中使用它,并且它可以无缝运行。
I am surprised that no one has given reference to Otto event Bus library
http://square.github.io/otto/
I have been using this in my android apps and it works seamlessly.
其他注释中未提及的另一种方法是使用 bindService() 从活动绑定到服务,并在 ServiceConnection 回调中获取服务的实例。如此处所述 http://developer.android.com/guide/components/bound- services.html
The other method that's not mentioned in the other comments is to bind to the service from the activity using bindService() and get an instance of the service in the ServiceConnection callback. As described here http://developer.android.com/guide/components/bound-services.html
绑定是另一种通信方式
在Activity中实现接口
提供方法的实现
将活动绑定到服务
的 实现
当 Service 绑定和取消绑定时注册和取消注册回调
活动。
初始化回调
在需要时调用回调方法
Binding is another way to communicate
Implement the interface in the Activity
Provide the implementation for the method
Bind the Activity to Service
Register and Unregister Callback when the Service gets bound and unbound with
Activity.
Initialize callback
Invoke the callback method whenever needed
另一种方法是通过活动和服务本身使用带有假模型类的观察者,实现 MVC 模式变体。我不知道这是否是实现这一目标的最佳方法,但这是对我有用的方法。如果您需要一些示例,请询问,我会发布一些内容。
Another way could be using observers with a fake model class through the activity and the service itself, implementing an MVC pattern variation. I don't know if it's the best way to accomplish this, but it's the way that worked for me. If you need some example ask for it and i'll post something.
除了本问题中已经回答的 LocalBroadcastManager 、事件总线和 Messenger 之外,我们还可以使用 Pending Intent 从服务进行通信。
正如我的博客文章中此处所述
Besides LocalBroadcastManager , Event Bus and Messenger already answered in this question,we can use Pending Intent to communicate from service.
As mentioned here in my blog post
我的方法:
管理从服务/活动发送和接收消息的类:
在活动中示例:
在服务中示例:
从活动/服务发送消息:
工作原理:
在您启动或绑定服务的活动上。
服务的“OnBind”方法将Binder返回给他的MessageManager,在Activity中通过“Service Connection”接口方法实现“OnServiceConnected”你得到这个IBinder并初始化你的MessageManager使用它。
在 Activity 初始化其 MessageManager 后,MessageHandler 向服务发送并握手,以便它可以设置其“MessageHandler”发送者( MessageManager 中的“private Messenger mMsgSender;”)。执行此操作后,服务就知道谁向其发送了消息。
您还可以使用 MessageManager 中的 Messenger“发送者”列表/队列来实现此目的,以便您可以将多条消息发送到不同的活动/服务,或者您可以使用 MessageManager 中的 Messenger“接收者”列表/队列,以便您可以接收多条消息来自不同活动/服务的消息。
在“MessageManager”实例中,您有收到的所有消息的列表。
正如您所看到的,使用此“MessageManager”实例的“Activity's Messenger”和“Service Messenger”之间的连接是自动的,它是通过“OnServiceConnected”方法并通过使用“Handshake”来完成的。
希望这对您有帮助:) 非常感谢!
再见:D
My method:
Class to manage send and receive message from/to service/activity:
In Activity Example:
In Service Example:
Send a message from Activity / Service:
How this works:
on the activity you start or bind the service.
The service "OnBind" methods return the Binder to his MessageManager, the in the Activity through the "Service Connection" interface methods implementation "OnServiceConnected" you get this IBinder and init you MessageManager using it.
After the Activity has init his MessageManager the MessageHandler send and Handshake to the service so it can set his "MessageHandler" sender ( the "private Messenger mMsgSender;" in MessageManager ). Doing this the service know to who send his messages.
You can also implement this using a List/Queue of Messenger "sender" in the MessageManager so you can send multiple messages to different Activities/Services or you can use a List/Queue of Messenger "receiver" in the MessageManager so you can receive multiple message from different Activities/Services.
In the "MessageManager" instance you have a list of all messages received.
As you can see the connection between "Activity's Messenger" and "Service Messenger" using this "MessageManager" instance is automatic, it is done through the "OnServiceConnected" method and through the use of the "Handshake".
Hope this is helpful for you :) Thank you very much!
Bye :D
通过代码示例来跟进 @MrSnowflake 的回答。
这是 XABBER 现在开源的
Application
类。Application
类集中并协调Listeners
和 ManagerInterfaces 等。各种管理器都是动态加载的。在 Xabber 中启动的Activity's
将报告它们是什么类型的Listener
。当Service
启动时,它会向Application
类报告已启动的情况。现在,要向Activity
发送消息,您所要做的就是使您的Activity
成为您所需类型的侦听器
。在OnStart()
OnPause()
中注册/取消注册。Service
可以向Application
类请求它需要与之通信的listener
,如果存在,那么 Activity 就可以接收了。浏览
Application
类,您会发现还有更多的事情发生。To follow up on @MrSnowflake answer with a code example.
This is the XABBER now open source
Application
class. TheApplication
class is centralising and coordinatingListeners
and ManagerInterfaces and more. Managers of all sorts are dynamically loaded.Activity´s
started in the Xabber will report in what type ofListener
they are. And when aService
start it report in to theApplication
class as started. Now to send a message to anActivity
all you have to do is make yourActivity
become alistener
of what type you need. In theOnStart()
OnPause()
register/unreg. TheService
can ask theApplication
class for just thatlistener
it need to speak to and if it's there then the Activity is ready to receive.Going through the
Application
class you'll see there's a loot more going on then this.正如 Madhur 提到的,您可以使用总线进行通信。
如果使用总线,您有一些选择:
Otto 事件总线库(已弃用,支持 RxJava)
http:// /square.github.io/otto/
Green Robot 的 EventBus
http://greenrobot.org/eventbus/< /a>
NYBus(RxBus,使用 RxJava 实现。与 EventBus 非常相似)
https://github.com/MindorksOpenSource /纽约巴士
As mentioned by Madhur, you can use a bus for communication.
In case of using a Bus you have some options:
Otto event Bus library (deprecated in favor of RxJava)
http://square.github.io/otto/
Green Robot’s EventBus
http://greenrobot.org/eventbus/
NYBus (RxBus, implemented using RxJava. very similar to the EventBus)
https://github.com/MindorksOpenSource/NYBus