Android中的IPC方式—— Bundle文件共享Messenger

Posted Young_xiaoT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android中的IPC方式—— Bundle文件共享Messenger相关的知识,希望对你有一定的参考价值。

1. 使用Bundle

android中的Activity、Service和Receiver都是支持在 Intent 中传递 Bundle 数据的,Bundle实现了 Parcelable 接口,它可以方便的在不同进程间传输。当我们在一个进程中启动了另一个进程的 Activity、Service 和 Receiver,就可以在 Bundle 中附加需要传输给远程进程的信息并通过 Intent 发送。注意:传输的数据必须能够被序列化,比如基本数据类型、实现Serializable 或 Parcelable接口的对象以及Android支持的特殊对象。

考虑这么一种情况,A进程正在计算,计算完成后它要启动B进程的一个组件并把计算结果传递给B进程,可是这个计算结果不支持放入Bundle中,因此无法使用Intent来传输。可以这么考虑来解决:通过Intent启动进程B的一个Service组件(比如IntentService),让Service在后台进行计算,计算完毕后再启动B进程中真正要启动的目标组件,由于Service也运行在B进程中,所有目标组件就可以直接获取计算结果。

2. 使用文件共享

共享文件也是一种很好的进程间通信方式,两个进车通过读/写同一个文件来交换数据。在Android系统中,可以并发的读/写文件,甚至两个线程可以同时对同一个文件进行读/写操作。还可以序列化一个对象到文件系统中的同时在另一个进程中恢复这个对象 。关键代码如下:

文件共享的方式要注意并发的问题,考虑使用线程同步来限制多个线程的写操作。

//MainActivity.java

private void persistToFile() 
        new Thread(new Runnable() 
            @Override
            public void run() 
                User user = new User(1, "hello", true);
                File dir = new File(getFilesDir().getAbsolutePath() + File.separator + "User");

                if (!dir.exists())
                    dir.mkdir();

                File cacheFile = new File(getFilesDir().getAbsolutePath() + File.separator + "User" + File.separator + "usercache");

                ObjectOutputStream objectOutputStream = null;
                try 
                    objectOutputStream = new ObjectOutputStream(new FileOutputStream(cacheFile));
                    objectOutputStream.writeObject(user);
                    Log.d("MainActivity", "persist user: " + user);
                 catch (IOException e) 
                    e.printStackTrace();
                 finally 
                    if (objectOutputStream != null) 
                        try 
                            objectOutputStream.close();
                         catch (IOException e) 
                            e.printStackTrace();
                        
                    
                

            
        ).start();
    
//SecondActivity
private void recoverFromFile() 
        new Thread(new Runnable() 
            @Override
            public void run() 
                User user = null;
                File cacheFile = new File(getFilesDir().getAbsolutePath() + File.separator + "User" + File.separator + "usercache");
                ObjectInputStream objectInputStream = null;

                try 
                    objectInputStream = new ObjectInputStream(new FileInputStream(cacheFile));
                    user = (User) objectInputStream.readObject();
                    Log.d("SecondActivity", "recover user" + user);
                 catch (IOException e) 
                    e.printStackTrace();
                 catch (ClassNotFoundException e) 
                    e.printStackTrace();
                 finally 
                
            
        ).start();
    

使用Messenger

Messenger可以翻译为信使,通过它可以在不同进程中传递Message对象,在Message中放入需要传递的数据,就可以轻松实现数据的进程间传递。Messenger是一种轻量级的 IPC 方案,它实现了Parcelable接口,底层实现是 AIDL。这个可以从它的构造方法看出:

    public Messenger(Handler target) 
        mTarget = target.getIMessenger();
    
    public Messenger(IBinder target) 
        mTarget = IMessenger.Stub.asInterface(target);
    

实现一个Messenger有如下几个步骤,分为服务端和客户端

(1)服务端进程
在服务端创建一个Service来处理客户端的连接请求,同时创建一个Handler并通过它来创建一个Messenger对象,然后在Service的 onBind 中返回这个Messenger 对象底层的 Binder 即可。
(2)客户端进程
客户端进程中,首先要绑定服务端的Service,绑定成功后用服务端返回的 IBinder 对象创建一个Message对象 。 如果需要服务端能够回应客户端,需要创建一个Handler并创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数传递给服务端,服务端通过这个replay参数就可以回应客户端。下面看两个例子:



(1)服务端接受客户端发送的消息

服务端代码,MessengerHandler用来处理客户端发送的消息,并从消息中取出客户端发来的文本信息。而 mMessenger 是一个Messenger对象,它和MessengerHandler相关联,并在onBind方法中返回它里面的 Binder 对象,可以看出,这里Messenger的作用是将客户端发送的消息 传递给MessengerHandler处理。

public class MessengerService extends Service 

    private static final String TAG = "MessengerService";

    private static class MessengerHandler extends Handler 
        @Override
        public void handleMessage(Message msg) 

            switch (msg.what) 
                case MyConstants.MSG_FROM_CLIENT:
                    Log.d(TAG, "receive msg from Client:" + msg.getData().getString("msg"));
                    break;
                default:
                    super.handleMessage(msg);

            
        
    

    private final Messenger mMessenger = new Messenger(new MessengerHandler());

    @Nullable
    @Override
    public IBinder onBind(Intent intent) 
        return messenger.getBinder();
    

客户端代码,首先要绑定远程的Messenger,绑定成功后,根据服务端返回的Binder对象创建Messenger对象,并使用此对象向服务端发送消息。

public class MessengerActivity extends AppCompatActivity 

    private static final String TAG = "MessengerActivity";

    private Messenger mServiece;

    private ServiceConnection coon = new ServiceConnection() 
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) 
            mServiece = new Messenger(iBinder);
            Message msg = Message.obtain();
            Bundle data = new Bundle();
            data.putString("msg", "hello, this is client");
            msg.setData(data);
            try 
                mServiece.send(msg);
             catch (RemoteException e) 
                e.printStackTrace();
            
        

        @Override
        public void onServiceDisconnected(ComponentName componentName) 

        
    ;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messenger);

        Intent intent = new Intent(this, MessengerService.class);
        bindService(intent, coon, BIND_AUTO_CREATE);


    

    @Override
    protected void onDestroy() 
        unbindService(coon);
        super.onDestroy();
    

log

com.example.mac.processdemo:remote D/MessengerService: receive msg from Client:hello, this is client

在Messenger中进行数据传递必须将数据放入Message中,而Messenger和Message都实现了Parcelable接口,因此可以跨进程传输。


(2)服务端接受客户端接受的消息,并向客户端做出回应

服务端代码,MessengerHandler收到消息后,立即回复一条消息给客户端

public class MessengerService extends Service 

    private static final String TAG = "MessengerService";

    private static class MessengerHandler extends Handler 
        @Override
        public void handleMessage(Message msg) 

            switch (msg.what) 
                case MyConstants.MSG_FROM_CLIENT:
                    Log.d(TAG, "receive msg from Client: " + msg.getData().getString("msg"));
                    Messenger client = msg.replyTo;
                    Message replyMessage = Message.obtain(null,MyConstants.MSG_FROM_SERVICE);
                    Bundle bundle = new Bundle();
                    bundle.putString("reply","收到了来自客户端的消息");
                    replyMessage.setData(bundle);
                    try 
                        client.send(replyMessage);
                     catch (RemoteException e) 
                        e.printStackTrace();
                    
                    break;
                default:
                    super.handleMessage(msg);

            
        
    

    private final Messenger messenger = new Messenger(new MessengerHandler());

    @Nullable
    @Override
    public IBinder onBind(Intent intent) 
        return messenger.getBinder();
    

客户端,也需要准备一个接收消息的Messenger和Handler,注意:当客户端发送消息时,需要把接收服务端回复的Messenger通过Message的replayTo参数传递给服务端

public class MessengerActivity extends AppCompatActivity 

    private static final String TAG = "MessengerActivity";

    private Messenger mServiece;

    private Messenger mGetReplayMessenger = new Messenger(new MessengerHandler());

    private ServiceConnection coon = new ServiceConnection() 
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) 
            mServiece = new Messenger(iBinder);
            Message msg = Message.obtain();
            Bundle data = new Bundle();
            data.putString("msg", "hello, this is client");
            msg.setData(data);
            /**
             *  注意:当客户端发送消息时,需要把接收服务端回复的Messenger通过Message的replayTo参数传递给服务端
             */
            msg.replyTo = mGetReplayMessenger;
            try 
                mServiece.send(msg);
             catch (RemoteException e) 
                e.printStackTrace();
            
        

        @Override
        public void onServiceDisconnected(ComponentName componentName) 

        
    ;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messenger);

        Intent intent = new Intent(this, MessengerService.class);
        bindService(intent, coon, BIND_AUTO_CREATE);


    

    @Override
    protected void onDestroy() 
        unbindService(coon);
        super.onDestroy();
    

    private static class MessengerHandler extends Handler 

        @Override
        public void handleMessage(Message msg) 
            switch (msg.what) 
                case MyConstants.MSG_FROM_SERVICE:
                    Log.d(TAG, "receive msg from Service: " + msg.getData().getString("reply"));
                    break;
                default:
                    super.handleMessage(msg);
            

        
    

以上是关于Android中的IPC方式—— Bundle文件共享Messenger的主要内容,如果未能解决你的问题,请参考以下文章

Android中实现IPC的几种方式详细分析及比较

android ipc通信机制之之三,进程通讯方式。

Android——IPC机制IPC概念以及Binder机制

Android之使用Bundle进行IPC

Android:IPC之AIDL的学习和总结

IPC机制——使用Bundle文件共享Messenger