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

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

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).

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

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

编辑:

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


当前回答

除了LocalBroadcastManager,事件总线和信使已经回答了这个问题,我们可以使用未决意图从服务通信。

正如我在博客中提到的

Communication between service and Activity can be done using PendingIntent.For that we can use createPendingResult().createPendingResult() creates a new PendingIntent object which you can hand to service to use and to send result data back to your activity inside onActivityResult(int, int, Intent) callback.Since a PendingIntent is Parcelable , and can therefore be put into an Intent extra,your activity can pass this PendingIntent to the service.The service, in turn, can call send() method on the PendingIntent to notify the activity via onActivityResult of an event. Activity 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); } } Service 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); } } } } }

其他回答

你也可以像EventBus一样使用LiveData。

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
    }
}

然后从您的活动中添加一个观察者。

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

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

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

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

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

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

绿色机器人的EventBus

http://greenrobot.org/eventbus/

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

https://github.com/MindorksOpenSource/NYBus

绑定是另一种通信方式

创建回调

public interface MyCallBack{

   public void getResult(String result);

}

活动方面:

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. 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 ); } }

服务端:

Initialize callback Invoke the callback method whenever needed 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; } }

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

我的方法:

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

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);

这是如何工作的:

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.

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

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

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

希望这对你有帮助:)非常感谢! 再见:D