代码之家  ›  专栏  ›  技术社区  ›  Scott Saunders

如何让Android服务与活动进行通信

  •  229
  • Scott Saunders  · 技术社区  · 15 年前

    我正在写我的第一个Android应用程序,并试图让我的头围绕服务和活动之间的通信。我有一个后台运行的服务,可以做一些GPS和基于时间的日志记录。我将有一个用于启动和停止服务的活动。

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

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

    似乎我应该能够确定服务是否正在运行,如果正在运行,那么将活动添加为侦听器。然后,当活动暂停或停止时,作为侦听器删除该活动。这真的有可能吗?我唯一能想到的方法是让活动实现parcelable并构建一个aidl文件,这样我就可以通过服务的远程接口传递它。不过,这似乎有点过分杀伤力,我不知道该活动应该如何实现writetoparcel()/readfromparcel()。

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

    编辑:

    对于以后感兴趣的人来说,在sample s目录下有来自Google的通过aidl处理这个问题的示例代码:/apis/app/remoteservice.java

    12 回复  |  直到 6 年前
        1
  •  82
  •   MrSnowflake    11 年前

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

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

    在你的情况下,我会选择3。对它自己的服务进行静态引用,并将其填充到onCreate()中:

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

    生成静态函数 MyService getInstance() ,返回静态 sInstance .

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

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

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

        2
  •  243
  •   Balder    6 年前

    询问者可能很久以前就离开过这里了,但如果有人搜索这个…

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

    在活动中添加广播接收器。注册它以在onresume中接收一些自定义意图,并在onpause中注销它。然后,当您想发送状态更新或您拥有的内容时,从您的服务中发送这个意图。

    如果其他应用程序听取了你的意图,确保你不会不高兴(有人会做任何恶意的事情吗?)但除此之外,你应该没事。

    请求代码示例:

    为我服务,我有:

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

    (refreshtask.refresh_data_intent只是一个常量字符串。)

    在我的听力活动中,我定义了我的广播接收器:

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

    现在,我的活动正在监听我的服务说“嘿,去更新你自己。”我可以按意图传递数据,而不是更新数据库表,然后返回到我的活动中查找更改,但是由于我希望更改仍然存在,所以通过DB传递数据是有意义的。

        3
  •  37
  •   Piyush    8 年前

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

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

        4
  •  18
  •   Madhur Ahuja    11 年前

    我很惊讶没有人提到奥托事件总线库

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

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

        5
  •  18
  •   PearsonArtPhoto    10 年前

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

    在活动中,使用相应的信使创建一个处理程序。这将处理来自您服务的消息。

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

    通过将信使附加到消息,可以将其传递给服务:

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

    完整的示例可以在API演示中找到: MessengerService and MessengerServiceActivity . 有关myService的工作方式,请参阅完整的示例。

        6
  •  7
  •   miguel    10 年前

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

        7
  •  2
  •   ReDirEct__    13 年前

    另一种方法是通过活动和服务本身使用假模型类的观察者,实现MVC模式变体。我不知道这是否是实现这一目标的最佳方式,但这是我的工作方式。如果你需要一些例子的话,我会贴一些东西。

        8
  •  2
  •   Erik    11 年前

    要跟进@mrsnowflake,请用代码示例回答。 This is the XABBER now open source Application class . 这个 应用 班级集中协调 Listeners 以及管理器接口等。所有类型的管理器都是动态加载的。 Activity´s 在xabber中启动将报告 Listener 他们是。当一个 Service 开始报告给 应用 开始时初始化。现在向 Activity 你所要做的就是 活动 成为 listener 你需要什么类型的。在 OnStart() OnPause() 注册/取消注册。这个 服务 可以问 应用 就为了这个课 听众 它需要与之对话,如果它在那里,那么活动就可以接收了。

    通过 应用 班上,你会看到有更多的战利品发生。

        9
  •  1
  •   zeenosaur    6 年前

    您也可以使用 LiveData 就像一个 EventBus .

    class MyService : LifecycleService() {
        companion object {
            var BUS = MutableLiveData<Object>()
        }
    
        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
        }
    })
    

    你可以从中了解更多 blog.

        10
  •  0
  •   Mahpooya    7 年前

    如Madhur所述,您可以使用总线进行通信。

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

    Otto事件总线库(已弃用,取而代之的是RxJava)

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

    绿色机器人的eventbus

    http://greenrobot.org/eventbus/

    nybus(rxbus,使用rxjava实现。非常类似于eventbus)

    https://github.com/MindorksOpenSource/NYBus

        11
  •  0
  •   Android Developer    7 年前

    另外 本地广播管理器、事件总线和通讯器 已经回答了这个问题,我们可以使用 待定意图 从服务中沟通。

    如前所述 here 在我的博客文章中

    服务和活动之间的通信可以使用 悬而未决。为此我们可以使用 创建挂起的结果 ().creatependingresult()创建新的 挂起内容对象,您可以将其传递给服务以使用和发送 在onActivityResult(int,int, 意图)回调。因为PendingContent是Parcelable,并且可以 因此,你的活动可以通过一个额外的意图。 挂起与服务的内容。服务可以依次调用send()。 通过PendingContent通知活动的方法 事件的OnActivityResult。

    活动

    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);
    
                    }
                }
            }
        }
    }
    
        12
  •  0
  •   Z3R0    6 年前

    我的方法:

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

    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”方法将绑定器返回给其messagemanager,在活动中,通过“service connection”接口方法实现“onserviceconnected”,您将得到这个ibinder并使用它初始化messagemanager。 在活动初始化其messagemanager之后,messagehandler将向服务发送和握手,以便它可以设置其“messagehandler”发送方(messagemanager中的“private messagenger mmsgssender”)。这样做,服务人员就知道是谁发送了他的信息。

    您还可以使用messagemanager中的messenger“sender”列表/队列来实现此功能,这样您就可以向不同的活动/服务发送多条消息,或者使用messagemanager中的messenger“receiver”列表/队列来接收来自不同活动/服务的多条消息。CES。

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

    如您所见,使用此“messagemanager”实例的“活动的信使”和“服务信使”之间的连接是自动的,它是通过“onServiceConnected”方法和使用“握手”来完成的。

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