如何让Android服务与活动通信

我正在编写我的第一个Android应用程序,试图弄清楚服务和活动之间的通信。我有一个服务,将在后台运行,并做一些gps和基于时间的日志记录。我将有一个活动,将用于启动和停止服务。

因此,首先,我需要能够确定当活动启动时服务是否正在运行。这里还有一些其他的问题,所以我想我可以解决(但请随意提供建议)。

我真正的问题是:如果活动正在运行,服务已经启动,我需要一种方法让服务向活动发送消息。简单的字符串和整数在这一点上-状态消息。消息不会定期发生,所以我认为如果有其他方法,轮询服务不是一个好方法。我只想在用户启动活动时进行此通信-我不想从服务启动活动。换句话说,如果您启动了Activity并且服务正在运行,当一些有趣的事情发生时,您将在Activity UI中看到一些状态消息。如果您不启动Activity,您将看不到这些消息(它们不是那么有趣)。

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

有没有更简单或更好的方法?谢谢你的帮助。

编辑:

对于稍后对此感兴趣的人来说,在示例目录:/apis/app/RemoteService.java中有来自谷歌的通过AIDL处理此问题的示例代码

170607 次浏览

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

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

在你的情况下,我选择第三种。对它自己的服务做一个静态引用,并在onCreate()中填充它:

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

创建一个静态函数MyService getInstance(),该函数返回静态sInstance

然后在Activity.onCreate()中启动服务,异步等待直到服务实际启动(你可以让你的服务通过向活动发送一个意图来通知你的应用程序它已经准备好了)并获取它的实例。当您拥有实例时,将您的服务侦听器对象注册到您的服务,您就完成了设置。注意:当在Activity中编辑view时,你应该在UI线程中修改它们,服务可能会运行自己的线程,所以你需要调用Activity.runOnUiThread()

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

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

提问者可能早就跳过了这个,但以防其他人搜索这个…

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

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

确保你不会不高兴,如果一些其他应用程序监听你的Intent(有人会做任何恶意的事情吗?),但除此之外,你应该是好的。

代码示例:

在我的工作中,我有这个:

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

(RefreshTask.REFRESH_DATA_INTENT只是一个常量字符串。)

在我的听力活动中,我定义了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中传递数据,而不是更新数据库表,然后返回到我的活动中寻找更改,但由于我希望更改始终保持,因此通过DB传递数据是有意义的。

使用LocalBroadcastManager来注册一个接收器来监听应用程序内部本地服务发送的广播,参考如下:

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

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

在Activity中,创建带有相应Messenger的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 = Message.obtain(null, MyService.ADD_RESPONSE_HANDLER);
message.replyTo = messenger;
try {
myService.send(message);
catch (RemoteException e) {
e.printStackTrace();
}

完整的例子可以在API演示中找到:MessengerService和MessengerServiceActivity。关于MyService如何工作,请参阅完整的示例。

另一种方法是通过活动和服务本身使用带有假模型类的观察者,实现MVC模式变化。我不知道这是否是最好的方法,但这种方法对我来说很有效。如果你需要一些例子,我会张贴一些东西。

用一个代码示例来跟进@ snowflake先生的回答。 Application5。Application类集中并协调Listeners和ManagerInterfaces等。所有类型的管理器都是动态加载的。在Xabber中开始的Activity´s将报告它们是什么类型的Listener。当Service启动时,它报告给Application类作为启动。现在要向Activity发送消息,你所要做的就是使你的Activity成为你需要的类型的listener。在Application0 Application1寄存器/unreg。Service可以向Application类请求它需要与之对话的listener,如果它在那里,则活动已经准备好接收。< / p >

通过Application类,你会看到有更多的战利品比这个。

我很惊讶没有人给奥托事件巴士库参考

http://square.github.io/otto/ < a href = " http://square.github.io/otto/ " > < / >

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

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

正如Madhur提到的,您可以使用总线进行通信。

在使用总线的情况下,您有一些选择:

Otto事件总线库(已弃用,支持RxJava)

< a href = " http://square.github。Io /otto/" rel="nofollow noreferrer">http://square.github.io/otto/ .

绿色机器人的EventBus

http://greenrobot.org/eventbus/

NYBus (RxBus,使用RxJava实现。非常类似于EventBus)

https://github.com/MindorksOpenSource/NYBus

除了在这个问题中已经回答了LocalBroadcastManager,事件总线和信使之外,我们还可以使用悬而未决的意图从服务进行通信。

正如我在博客文章中提到的在这里

服务和活动之间的通信可以使用 PendingIntent。我们可以利用它 createPendingResult().createPendingResult()创建一个新的 PendingIntent对象,你可以把它交给服务使用和发送 结果数据返回到您的活动内onActivityResult(int, int, 意图)回调。因为一个PendingIntent是可打包的,并且可以 因此被放入一个额外的意图,你的活动可以传递这个 服务的PendingIntent。服务可以调用send() 方法来通知活动

. onactivityevent的结果

活动

public class PendingIntentActivity extends AppCompatActivity
{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


PendingIntent pendingResult = createPendingResult(
100, new Intent(), 0);
Intent intent = new Intent(getApplicationContext(), PendingIntentService.class);
intent.putExtra("pendingIntent", pendingResult);
startService(intent);


}


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 100 && resultCode==200) {
Toast.makeText(this,data.getStringExtra("name"),Toast.LENGTH_LONG).show();
}
super.onActivityResult(requestCode, resultCode, data);
}
}

服务

public class PendingIntentService extends Service {


private static final String[] items= { "lorem", "ipsum", "dolor",
"sit", "amet", "consectetuer", "adipiscing", "elit", "morbi",
"vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam",
"vel", "erat", "placerat", "ante", "porttitor", "sodales",
"pellentesque", "augue", "purus" };
private PendingIntent data;


@Override
public void onCreate() {
super.onCreate();
}


@Override
public int onStartCommand(Intent intent, int flags, int startId) {


data = intent.getParcelableExtra("pendingIntent");


new LoadWordsThread().start();
return START_NOT_STICKY;
}


@Override
public IBinder onBind(Intent intent) {
return null;
}


@Override
public void onDestroy() {
super.onDestroy();
}


class LoadWordsThread extends Thread {
@Override
public void run() {
for (String item : items) {
if (!isInterrupted()) {


Intent result = new Intent();
result.putExtra("name", item);
try {
data.send(PendingIntentService.this,200,result);
} catch (PendingIntent.CanceledException e) {


e.printStackTrace();
}
SystemClock.sleep(400);


}
}
}
}
}

你也可以使用类似EventBusLiveData

class MyService : LifecycleService() {
companion object {
val BUS = MutableLiveData<Any>()
}


override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)


val testItem : Object


// expose your data
if (BUS.hasActiveObservers()) {
BUS.postValue(testItem)
}


return START_NOT_STICKY
}
}

然后从Activity中添加一个观察者。

MyService.BUS.observe(this, Observer {
it?.let {
// Do what you need to do here
}
})

你可以从这个博客。读到更多

我的方法:

类来管理从/到服务/活动的发送和接收消息:

import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;


import java.util.ArrayList;
import java.util.List;


public class MessageManager {


public interface IOnHandleMessage{
// Messages
int MSG_HANDSHAKE = 0x1;


void onHandleMessage(Message msg);
}


private static final String LOGCAT = MessageManager.class.getSimpleName();


private Messenger mMsgSender;
private Messenger mMsgReceiver;
private List<Message> mMessages;


public MessageManager(IOnHandleMessage callback, IBinder target){
mMsgReceiver = new Messenger(new MessageHandler(callback, MessageHandler.TYPE_ACTIVITY));
mMsgSender = new Messenger(target);
mMessages = new ArrayList<>();
}


public MessageManager(IOnHandleMessage callback){
mMsgReceiver = new Messenger(new MessageHandler(callback, MessageHandler.TYPE_SERVICE));
mMsgSender = null;
mMessages = new ArrayList<>();
}


/* START Getter & Setter Methods */
public Messenger getMsgSender() {
return mMsgSender;
}


public void setMsgSender(Messenger sender) {
this.mMsgSender = sender;
}


public Messenger getMsgReceiver() {
return mMsgReceiver;
}


public void setMsgReceiver(Messenger receiver) {
this.mMsgReceiver = receiver;
}


public List<Message> getLastMessages() {
return mMessages;
}


public void addMessage(Message message) {
this.mMessages.add(message);
}
/* END Getter & Setter Methods */


/* START Public Methods */
public void sendMessage(int what, int arg1, int arg2, Bundle msgData){
if(mMsgSender != null && mMsgReceiver != null) {
try {
Message msg = Message.obtain(null, what, arg1, arg2);
msg.replyTo = mMsgReceiver;
if(msgData != null){
msg.setData(msgData);
}
mMsgSender.send(msg);
} catch (RemoteException rE) {
onException(rE);
}
}
}


public void sendHandshake(){
if(mMsgSender != null && mMsgReceiver != null){
sendMessage(IOnHandleMessage.MSG_HANDSHAKE, 0, 0, null);
}
}
/* END Public Methods */


/* START Private Methods */
private void onException(Exception e){
Log.e(LOGCAT, e.getMessage());
e.printStackTrace();
}
/* END Private Methods */


/** START Private Classes **/
private class MessageHandler extends Handler {


// Types
final static int TYPE_SERVICE = 0x1;
final static int TYPE_ACTIVITY = 0x2;


private IOnHandleMessage mCallback;
private int mType;


public MessageHandler(IOnHandleMessage callback, int type){
mCallback = callback;
mType = type;
}


@Override
public void handleMessage(Message msg){
addMessage(msg);
switch(msg.what){
case IOnHandleMessage.MSG_HANDSHAKE:
switch(mType){
case TYPE_SERVICE:
setMsgSender(msg.replyTo);
sendHandshake();
break;
case TYPE_ACTIVITY:
Log.v(LOGCAT, "HERE");
break;
}
break;
default:
if(mCallback != null){
mCallback.onHandleMessage(msg);
}
break;
}
}


}
/** END Private Classes **/


}

在活动示例中:

public class activity extends AppCompatActivity
implements     ServiceConnection,
MessageManager.IOnHandleMessage {


[....]


private MessageManager mMessenger;


private void initMyMessenger(IBinder iBinder){
mMessenger = new MessageManager(this, iBinder);
mMessenger.sendHandshake();
}


private void bindToService(){
Intent intent = new Intent(this, TagScanService.class);
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
/* START THE SERVICE IF NEEDED */
}


private void unbindToService(){
/* UNBIND when you want (onDestroy, after operation...)
if(mBound) {
unbindService(mServiceConnection);
mBound = false;
}
}


/* START Override MessageManager.IOnHandleMessage Methods */
@Override
public void onHandleMessage(Message msg) {
switch(msg.what){
case Constants.MSG_SYNC_PROGRESS:
Bundle data = msg.getData();
String text = data.getString(Constants.KEY_MSG_TEXT);
setMessageProgress(text);
break;
case Constants.MSG_START_SYNC:
onStartSync();
break;
case Constants.MSG_END_SYNC:
onEndSync(msg.arg1 == Constants.ARG1_SUCCESS);
mBound = false;
break;
}
}
/* END Override MessageManager.IOnHandleMessage Methods */


/** START Override ServiceConnection Methods **/
private class BLEScanServiceConnection implements ServiceConnection {


@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
initMyMessenger(iBinder);
mBound = true;
}


@Override
public void onServiceDisconnected(ComponentName componentName) {
mMessenger = null;
mBound = false;
}
}
/** END Override ServiceConnection Methods **/

业务举例:

public class Blablabla extends Service
implements     MessageManager.IOnHandleMessage {


[...]


private MessageManager mMessenger;


@Nullable
@Override
public IBinder onBind(Intent intent) {
super.onBind(intent);
initMessageManager();
return mMessenger.getMsgReceiver().getBinder();
}


private void initMessageManager(){
mMessenger = new MessageManager(this);
}


/* START Override IOnHandleMessage Methods */
@Override
public void onHandleMessage(Message msg) {
/* Do what you want when u get a message looking the "what" attribute */
}
/* END Override IOnHandleMessage Methods */

从活动/服务发送消息:

mMessenger.sendMessage(what, arg1, arg2, dataBundle);

这是如何工作的:

在您启动或绑定服务的活动上

。 服务“OnBind”方法将Binder返回给他的MessageManager,在活动中通过“service Connection”接口方法实现“onserviceconnconnected”,你得到这个IBinder并使用它init你的MessageManager。 在Activity init了他的MessageManager之后,MessageHandler发送和握手给服务,这样它就可以设置他的“MessageHandler”发送者(在MessageManager中是“私有的信使mMsgSender;”)。

.服务知道谁发送了他的消息

你也可以在MessageManager中使用信使的列表/队列“发送者”来实现这一点,这样你就可以向不同的活动/服务发送多个消息,或者你可以在MessageManager中使用信使的列表/队列“接收者”,这样你就可以从不同的活动/服务接收多个消息。

在“MessageManager”实例中,您有一个接收到的所有消息的列表。

正如你所看到的,使用这个“MessageManager”实例的“Activity’s Messenger”和“Service Messenger”之间的连接是自动的,它是通过“onserviceconnconnected”方法和“Handshake”的使用完成的。

希望这对你有帮助:)谢谢! 再见:D < / p >

绑定是另一种通信方式

创建回调

public interface MyCallBack{


public void getResult(String result);


}

活动方面:

  1. 在Activity中实现接口

  2. 提供方法的实现

  3. 将活动绑定到服务

  4. 注册和取消注册当服务被绑定和取消绑定时的回调 活动。< / p >

    public class YourActivity extends AppCompatActivity implements MyCallBack{
    
    
    private Intent notifyMeIntent;
    private GPSService gpsService;
    private boolean bound = false;
    
    
    @Override
    public void onCreate(Bundle sis){
    
    
    // activity code ...
    
    
    startGPSService();
    
    
    }
    
    
    @Override
    public void getResult(String result){
    // show in textView textView.setText(result);
    }
    
    
    @Override
    protected void onStart()
    {
    super.onStart();
    bindService();
    }
    
    
    @Override
    protected void onStop() {
    super.onStop();
    unbindService();
    }
    
    
    private ServiceConnection serviceConnection = new ServiceConnection() {
    
    
    @Override
    public void onServiceConnected(ComponentName className, IBinder service) {
    
    
    GPSService.GPSBinder binder = (GPSService.GPSBinder) service;
    gpsService= binder.getService();
    bound = true;
    gpsService.registerCallBack(YourActivity.this); // register
    
    
    }
    
    
    @Override
    public void onServiceDisconnected(ComponentName arg0) {
    bound = false;
    }
    };
    
    
    private void bindService() {
    
    
    bindService(notifyMeIntent, serviceConnection, Context.BIND_AUTO_CREATE);
    }
    
    
    private void unbindService(){
    if (bound) {
    gpsService.registerCallBack(null); // unregister
    unbindService(serviceConnection);
    bound = false;
    }
    }
    
    
    // Call this method somewhere to start Your GPSService
    private void startGPSService(){
    notifyMeIntent = new Intent(this, GPSService.class);
    startService(myIntent );
    }
    
    
    }
    

服务端:

  1. < p >初始化的回调

  2. 在需要时调用回调方法

     public class GPSService extends Service{
    
    
    private MyCallBack myCallback;
    private IBinder serviceBinder = new GPSBinder();
    
    
    public void registerCallBack(MyCallBack myCallback){
    this.myCallback= myCallback;
    }
    
    
    public class GPSBinder extends Binder{
    
    
    public GPSService getService(){
    return GPSService.this;
    }
    }
    
    
    @Nullable
    @Override
    public IBinder onBind(Intent intent){
    return serviceBinder;
    }
    }