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

        }
    }
}
时间: 2024-10-22 16:15:32

Android中的IPC方式(一)—— Bundle、文件共享、Messenger的相关文章

Android中进程间通信(IPC)方式总结

IPC为进程间通信或跨进程通信,是指两个进程进行进程间通信的过程.在PC和移动设备上一个进程指的是一个程序或者一个应用,所以我们可以将进程间通信简单理解为不同应用之间的通信,当然这种说法并不严谨. 在Android中,为每一个应用程序都分配了一个独立的虚拟机,或者说每个进程都分配一个独立的虚拟机,不同虚拟机在内存分配上有不同的地址空间,这就导致在不同的虚拟机互相访问数据需要借助其他手段.下面分别介绍一下在Android中进行实现IPC的方式. 1.使用Bundle 我们知道在Android中三大

Android 中的IPC机制

Android IPC 介绍 IPC是 Inter-Proscess Communication的缩写,含义为进程间的通讯或者跨进程通讯,是指两个进程之间进行数据交换的过程.按操作系统的中的描述,线程是CPU调度最小的单元,同时线程是一种有限的系统资源,而进程是指一个执行单元,在PC和移动设备上指一个程序或者一个应用.一个进程可以包含多个线程,因此进程和线程是包含于被包含的关系. IPC的使用场景就必须提到多进程,只有面对多进程这种场景下,才需要考虑进程间通讯.多进程的情况分为两种:第一种是一个

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

1.使用Bundle   ----> 用于android四大组件间的进程间通信 android的四大组件都可使用Bundle传递数据  所以如果要实现四大组件间的进程间通信 完全可以使用Bundle来实现 简单方便 2.使用文件共享  ---->用于单线程读写 这种方式在单线程读写的时候比较好用 如果有多个线程并发读写的话需要限制线程的同步读写 另外 SharePreference是个特例  它底层基于xml实现  但是系统对它的读写会基于缓存,也就是说再多进程模式下就变得不那么可靠了,有很大

Android中常见IPC方法总结

欢迎转载,转载请注明出处http://blog.csdn.net/l664675249/article/details/50654926 IPC (Interprocess communication)跨进程通信,是指在两个进程之间交换数据的过程.多进程通信一般分为两种情况.第一种,一个应用因为自身的需要采用多进程实现,比如某些模块由于特殊原因需要运行在单独的进程中.第二种情况,当前应用需要获得其它应用的数据,由于是两个应用,所以必须采用跨进程的方式.下面就对常用的IPC方法做一个总结. 使用B

Android中的Parcel机制 实现Bundle传递对象

Android中的Parcel机制    实现了Bundle传递对象    使用Bundle传递对象,首先要将其序列化,但是,在Android中要使用这种传递对象的方式需要用到Android Parcel机制,即,Android实现的轻量级的高效的对象序列化和反序列化机制. JAVA中的Serialize机制,译成串行化.序列化……,其作用是能将数据对象存入字节流当中,在需要时重新生成对象.主要应用是利用外部存储设备保存对象状态,以及通过网络传输对象等.        Android中的新的序列

Android中数据存储方式一:文件形式

总结在Android中,一共有数据存储的5种方式.今天做一个笔记的整理.关于以文件形式如何来保存数据. 1.在activity_main.xml设计好布局 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_pa

【转】Android中intent传递对象和Bundle的用法

原文网址:http://blog.csdn.net/lixiang0522/article/details/8642202 android中的组件间传递的对象一般实现Parcelable接口,当然也可以使用java的Serializable接口,前者是android专门设计的,效率更高,下面我们就来实现一个Parcelabel. 1. 创建一个类实现Parcelable接口,具体实现如下: [java] view plain copy package com.hebaijun.testparce

Android中使用PULL方式解析XML文件

Pull解析器的运行方式与 SAX 解析器相似.它提供了类似的事件,如:开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件.跟SAX不同的是, Pull解析器产生的事件是一个数字,而非方法,因此可以使用一个switch对感兴趣的事件进行处理.当元素开始解析时,调用parser.nextText()方法可以获取下一个Text类型节点的值. 下面我们通过Demo例子来介绍如何使用PULL机制来解析XML文件.先看下如下工程的目录结构: 按以下步骤进行操作: [1]

Android中通过SAX方式解析XML

每个访问网络的应用程序都有一个自己的服务器,我们可以向服务器提交数据,也可以从服务器上获取数据.那么,这些数据是用什么格式在网络上传输的呢?一般,我们会在网络上传输一些格式化的数据,这些数据有一定的结构和语义.另一方收到数据消息后就可以按照相同的结构规格来进行解析,从而获取到想要的那部分内容. 网络上传输数据最常用的格式有两种,XML和JSON.下面,我们介绍通过SAX方式来解析XML. 首先,进行准备一段XML格式的数据. get_data.xml 1 <apps> 2 <app>