如何让Android Service与Activity通信

发布于 2024-08-25 21:51:15 字数 783 浏览 2 评论 0原文

我正在编写我的第一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

忘羡 2024-09-01 21:51:15

提问者可能早已超越了这个,但万一其他人搜索这个......

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

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

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 in onResume and unregister it in onPause. 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:

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

(RefreshTask.REFRESH_DATA_INTENT is just a constant string.)

In my listening activity, I define my 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
        }
    }
}

I declare my receiver at the top of the class:

private DataUpdateReceiver dataUpdateReceiver;

I override onResume to add this:

if (dataUpdateReceiver == null) dataUpdateReceiver = new DataUpdateReceiver();
IntentFilter intentFilter = new IntentFilter(RefreshTask.REFRESH_DATA_INTENT);
registerReceiver(dataUpdateReceiver, intentFilter);

And I override onPause to add:

if (dataUpdateReceiver != null) unregisterReceiver(dataUpdateReceiver);

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.

憧憬巴黎街头的黎明 2024-09-01 21:51:15

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

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

在您的情况下,我会选择选项 3。对服务本身进行静态引用并将其填充到 onCreate( ):

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

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

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

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

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

There are three obvious ways to communicate with services:

  1. Using Intents
  2. Using AIDL
  3. Using the service object itself (as singleton)

In your case, I'd go with option 3. Make a static reference to the service it self and populate it in onCreate():

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

Make a static function MyService getInstance(), which returns the static sInstance.

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 call Activity.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.

地狱即天堂 2024-09-01 21:51:15

使用 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

怎会甘心 2024-09-01 21:51:15

您还可以使用像 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
    }
}

然后从您的 Activity 添加观察者。

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

您可以从此博客阅读更多内容。

You may also use LiveData that works like an EventBus.

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

Then add an observer from your Activity.

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

You can read more from this blog.

彩虹直至黑白 2024-09-01 21:51:15

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

在Activity中,创建一个Handler和对应的Messenger。这将处理来自您的服务的消息。

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 演示中找到: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.

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

The Messenger can be passed to the service by attaching it to a Message:

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

A full example can be found in the API demos: MessengerService and MessengerServiceActivity. Refer to the full example for how MyService works.

蒗幽 2024-09-01 21:51:15

我很惊讶没有人参考 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.

囚我心虐我身 2024-09-01 21:51:15

其他注释中未提及的另一种方法是使用 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

陌伤浅笑 2024-09-01 21:51:15

绑定是另一种通信方式

创建回调

public interface MyCallBack{

   public void getResult(String result);

}

活动方面:

  1. 在Activity中实现接口

  2. 提供方法的实现

  3. 将活动绑定到服务

    的 实现

  4. 当 Service 绑定和取消绑定时注册和取消注册回调
    活动。

    公共类 YourActivity 扩展 AppCompatActivity 实现 MyCallBack{
    
          私有意图notifyMeIntent;
          私人GPS服务gps服务;
          私有布尔边界= false;
    
          @覆盖
          公共无效onCreate(捆绑sis){
    
              // 活动代码...
    
              启动GPS服务();
    
          }
    
          @覆盖
          公共无效 getResult(字符串结果){
           // 在textView中显示 textView.setText(result);
          }
    
          @覆盖
          受保护无效 onStart()
          {
              super.onStart();
              绑定服务();
          }
    
          @覆盖
          受保护无效 onStop() {
              super.onStop();
              解除绑定服务();
          }
    
          私有ServiceConnection serviceConnection = new ServiceConnection() {
    
                @覆盖
                public void onServiceConnected(ComponentName className, IBinder 服务) {
    
                      GPSService.GPSBinder 绑定器 = (GPSService.GPSBinder) 服务;
                      gpsService=binder.getService();
                      界限=真;
                      gpsService.registerCallBack(YourActivity.this); // 登记
    
               }
    
               @覆盖
               公共无效onServiceDisconnected(ComponentName arg0){
                      绑定=假;
               }
          };
    
          私有无效bindService(){
    
               bindService(notifyMeIntent, serviceConnection, Context.BIND_AUTO_CREATE);
          }
    
          私有无效unbindService(){
               如果(绑定){
                     gpsService.registerCallBack(null); // 取消注册            
                     解除绑定服务(服务连接);
                     绑定=假;
                }
          }
    
          // 在某处调用此方法来启动您的 GPSService
          私有无效startGPSService(){
               notifyMeIntent = new Intent(this, GPSService.class);
               启动服务(myIntent);
          }
    
     }
    

服务端:

  1. 初始化回调

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

     公共类 GPSService 扩展服务{
    
         私有 MyCallBack myCallback;
         私有 IBinder serviceBinder = new GPSBinder();
    
         公共无效registerCallBack(MyCallBack myCallback){
              this.myCallback= myCallback;
         }
    
         公共类 GPSBinder 扩展 Binder{
    
             公共 GPSService getService(){
                  返回 GPSService.this;
             }
        }
    
        @可为空
        @覆盖
        公共IBinder onBind(Intent意图){
             返回serviceBinder;
        }
     }
    

Binding is another way to communicate

Create a callback

public interface MyCallBack{

   public void getResult(String result);

}

Activity side:

  1. Implement the interface in the Activity

  2. Provide the implementation for the method

  3. Bind the Activity to Service

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

Service Side:

  1. Initialize callback

  2. 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;
        }
     }
    
南冥有猫 2024-09-01 21:51:15

另一种方法是通过活动和服务本身使用带有假模型类的观察者,实现 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.

最冷一天 2024-09-01 21:51:15

除了本问题中已经回答的 LocalBroadcastManager 、事件总线和 Messenger 之外,我们还可以使用 Pending Intent 从服务进行通信。

正如我的博客文章中此处所述

服务和 Activity 之间的通信可以使用
PendingIntent.为此我们可以使用
createPendingResult().createPendingResult() 创建一个新的
您可以将其交给服务使用和发送的 PendingIntent 对象
结果数据返回到 onActivityResult(int, int,
Intent) 回调。因为 PendingIntent 是 Parcelable ,并且可以
因此被放入一个 Intent extra 中,你的 Activity 可以通过这个
服务的 PendingIntent。服务反过来可以调用 send()
PendingIntent 上的方法通过以下方式通知活动
事件的 onActivityResult。

活动

公共类 PendingIntentActivity 扩展了 AppCompatActivity
{
@覆盖
protected void onCreate(@Nullable Bundle savingInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

PendingIntent 待定结果 = createPendingResult(
100、新的Intent(), 0);
Intent意图 = new Intent(getApplicationContext(), PendingIntentService.class);
Intent.putExtra(“pendingIntent”,pendingResult);
启动服务(意图);

}

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

服务

public class PendingIntentService 扩展服务 {

    私人静态最终字符串[]项目= {“lorem”,“ipsum”,“dolor”,
            “坐”,“amet”,“consectetuer”,“adipiscing”,“elit”,“morbi”,
            “vel”、“ligula”、“vitae”、“arcu”、“aliquet”、“mollis”、“etiam”、
            “vel”,“erat”,“placerat”,“ante”,“porttitor”,“sodales”,
            “pellentesque”、“augue”、“purus”};
    私有 PendingIntent 数据;

    @覆盖
    公共无效 onCreate() {
        super.onCreate();
    }

    @覆盖
    公共int onStartCommand(Intent意图,int标志,int startId){

        数据 = Intent.getParcelableExtra("pendingIntent");

        新的LoadWordsThread().start();
        返回START_NOT_STICKY;
    }

    @覆盖
    公共 IBinder onBind(Intent 意图) {
        返回空值;
    }

    @覆盖
    公共无效onDestroy(){
        super.onDestroy();
    }

    类 LoadWordsThread 扩展线程 {
        @覆盖
        公共无效运行(){
            for(字符串项目:项目){
                if (!isInterrupted()) {

                    意图结果 = new Intent();
                    result.putExtra("名称", 项目);
                    尝试 {
                        data.send(PendingIntentService.this,200,结果);
                    } catch (PendingIntent.CanceledException e) {

                        e.printStackTrace();
                    }
                    系统时钟.睡眠(400);

                }
            }
        }
    }
}

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

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

                }
            }
        }
    }
}
清风疏影 2024-09-01 21:51:15

我的方法:

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

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,在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:

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 **/

}

In Activity Example:

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 **/

In Service Example:

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 */

Send a message from Activity / Service:

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

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

失而复得 2024-09-01 21:51:15

通过代码示例来跟进 @MrSnowflake 的回答。
这是 XABBER 现在开源的 ApplicationApplication 类集中并协调 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. The Application class is centralising and coordinating Listeners and ManagerInterfaces and more. Managers of all sorts are dynamically loaded. Activity´s started in the Xabber will report in what type of Listener they are. And when a Service start it report in to the Application class as started. Now to send a message to an Activity all you have to do is make your Activity become a listener of what type you need. In the OnStart() OnPause() register/unreg. The Service can ask the Application class for just that listener 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.

×眷恋的温暖 2024-09-01 21:51:15

正如 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文