Android 中的进程通信 Bundle 、文件共享、Messenger、AIDL、ContentProvider。
使用Bundle
Android四大组件都支持Intent传递Bundle数据的,由于Bundle实现了Parcelable接口,所以它可以方便地在不同的进程间传输。基于这一点,当我们在一个进程中启动了另一个进程的Activity、Service和Receiver,我们就可以在Bundle中附加我们需要传输给远程进程的信息,并通过Intent发出去。这是一种简单的进程间通信方式。
使用文件共享
文件共享方式很好理解,讲我们要传递的数据写入一个文件中,在另一个进程中来读取这个文件。因为文件共享是通过读取回复的,所以本质上是两个对象。而且文件共享的这种方式不支持并发读写。
使用Messenger
Messenger可以在不同进程中传递Message对象,在Messag中放入我们需要传递的数据,就可以轻松的实现数据的进程间传递了。Messenger的底层是AIDL,它对AIDL进行了封装所以使用起来会简单一些。实现一个Messenger分为服务端和客户端。
服务端代码
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.e(TAG,"receive msg from Client:"+msg.getData().getString("msg")); /** * 服务端回复 客户端 */ Messenger client = msg.replyTo; Message relpyMessage = Message.obtain(null,MyConstants.MSG_FROM_SERVICE); Bundle bundle = new Bundle(); bundle.putString("reply","消息收到了!"); relpyMessage.setData(bundle); try { client.send(relpyMessage); } catch (RemoteException e) { } break; default: super.handleMessage(msg); } } } private final Messenger mMessenger = new Messenger(new MessengerHandler()); @Nullable @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } } 首先我们需要创建一个service来处理客户端的连接请求,同事创建一个handle通过它来创建一个Messenger,然后在Service的onBind方法中返回这个Messenger的Binder。代码中可以看到MessengerHandler用来处理客户端发送的消息,并从消息中取出客户端发送过来的文本信息。并通过MessengerHandler创建一个Messenger对象,并在onBind方法中返回这个Messenger的Binder。注册Service,让其运行在单独的进程中。 <service android:name=".service.MessengerService" android:process=":remote" />客户端代码
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private Messenger mService; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = new Messenger(service); Message msg = Message.obtain(null, MyConstants.MSG_FROM_CLIENT); Bundle data = new Bundle(); data.putString("msg","hello, this is client."); msg.setData(data); /** * 将客户端接收消息的messenger传递给服务端 */ msg.replyTo = mGetReplyMessenger; try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler()); private static class MessengerHandler extends Handler{ @Override public void handleMessage(Message msg) { switch (msg.what){ case MyConstants.MSG_FROM_SERVICE: Log.e(TAG,"receive msg from Service:"+msg.getData().getString("reply")); break; default: super.handleMessage(msg); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /** * 绑定服务 */ Intent intent = new Intent(this, MessengerService.class); bindService(intent,mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { unbindService(mConnection); super.onDestroy(); } }客户端的实现,首先需要绑定上面服务端的远程服务,根据Service返回的Binder创建Messenger对象 并使用此对象向Service发送消息。注意传递的数据必须放在Message中。
使用AIDL
由于Messenger是以串行的方式处理消息的,当出现消息并发处理时Messenger就不太合适了。而且Messenger的作用主要是为了传递消息,很多时候我们可能需要跨进程调用方法,就需要使用AIDL了。
首先先创建AIDL接口。Android studio 创建aidl文件很简单 在工程下新建AIDL就可以了studio会自动在main下创建AIDL包如图:
aidl文件创建默认就是一个接口,在接口中声明两个接口方法。
import com.zrf.testaidl.testaidl.Book; import com.zrf.testaidl.testaidl.IOnNewBookArrivedListener; //aidl 接口 aidl接口中只支持方法,不支持声明静态常量 interface IBookManager { //获取书籍的方法 List<Book> getBookList(); // 添加书籍的方法 注意 传递的参数前要用 in 修饰 否则编译不过 //aidl 规定 除了基本数据数据类型,其他的类型必须标上方向 // in(输入性参数) out(输出型参数) inout(输入输出型参数) void addBook(in Book book); void registerListener(IOnNewBookArrivedListener listener); void unregisterListener(IOnNewBookArrivedListener listener); } 在AIDL文件中,并不是所有的数据类型都是可以使用的。AIDL支持的数据类型:
1、基本数据类型(int long char boolean double 等);
2、 String和CharSequence;
3、list:支持ArrayList和CoyOnWriteArrayList (CoyOnWriteArrayList 支持并发读写),里面的每个元素都必须能够被AIDL支持;
4、Map:只支持HashMap ,里面的每个元素必须被AIDL支持包括Key和value.
5、Parcelable:所有实现了Parcelable接口的对象
6、AIDL:所有AIDL接口本身也可以在AIDL中使用;
其中自定义的Parcelable对象和AIDL必须要显示Import进来。
如果AIDL文件中用到了自定义的Parcelable对象,必须创建一个和它同名的AIDL文件。
package com.zrf.testaidl.testaidl; // Declare any non-default types here with import statements import com.zrf.testaidl.testaidl.Book; parcelable Book; 上面讲述了如何定义AIDL接口,接下来就需要实现这个接口。先创建一个Service。 public class BookManagerService extends Service { private static final String TAG = "BMS"; /** * CopyOnWriteArrayList 支持并发读写 * 因为aidl是在service中运行的 会出现多个线程同时访问的情况 */ private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>(); // private CopyOnWriteArrayList<IOnNewBookArrivedListener> mListenerlist = new CopyOnWriteArrayList<>(); private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false); /** * RemoteCallbackList 用于管理IOnNewBookArrivedListener * RemoteCallbackList 是系统专门提供的用于删除出跨进程listener的接口。 * RemoteCallbackList 是一个泛型,支持管理任意的AIDL接口,所有的AIDL接口都继承 * */ private RemoteCallbackList<IOnNewBookArrivedListener> remoteCallbackList = new RemoteCallbackList<>(); /** * 通过 IBookManeger 创建一个 Binder */ private Binder binder = new IBookManager.Stub(){ @Override public List<Book> getBookList() throws RemoteException { return mBookList; } @Override public void addBook(Book book) throws RemoteException { mBookList.add(book); } @Override public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException { remoteCallbackList.register(listener); } @Override public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException { remoteCallbackList.unregister(listener); } }; @Override public void onCreate() { super.onCreate(); mBookList.add(new Book(1,"Android")); mBookList.add(new Book(2,"ios")); new Thread(new ServiceWorker()).start(); } @Override public void onDestroy() { mIsServiceDestoryed.set(true); super.onDestroy(); } /** * 实现每次添加新数据都通知客户端 * @param book * @throws RemoteException */ public void onNewBookArrived(Book book) throws RemoteException{ mBookList.add(book); Log.e(TAG,"onNewBookArrived, notify listeners:" + remoteCallbackList.getRegisteredCallbackCount()); final int N = remoteCallbackList.beginBroadcast(); for (int i=0;i<N;i++){ IOnNewBookArrivedListener listener = remoteCallbackList.getBroadcastItem(i); if (listener!=null){ listener.onNewBookArrived(book); } } remoteCallbackList.finishBroadcast(); } private class ServiceWorker implements Runnable{ @Override public void run() { while (!mIsServiceDestoryed.get()){ try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } int bookId = mBookList.size()+1; Book newBook = new Book(bookId,"new book:"+bookId); try { onNewBookArrived(newBook); } catch (RemoteException e) { e.printStackTrace(); } } } } @Nullable @Override public IBinder onBind(Intent intent) { return binder; } }接下来是客户端的
public class BookManegerAidlActivity extends AppCompatActivity { private static final String TAG = "BookManegerAidlActiity"; private static final int MESSAGE_NEW_BOOK_ARRIVED = 1; private IBookManager mRemoteBookManager; private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case MESSAGE_NEW_BOOK_ARRIVED: Log.e(TAG,"receive new book:"+msg.obj); break; default: super.handleMessage(msg); } } }; /** * 当service中的Binder死亡时重新连接 */ private IBinder.DeathRecipient mDeathrecipient = new IBinder.DeathRecipient(){ @Override public void binderDied() { if(mRemoteBookManager!=null){ mRemoteBookManager.asBinder().unlinkToDeath(mDeathrecipient,0); mRemoteBookManager = null; Intent intent = new Intent(BookManegerAidlActivity.this, BookManagerService.class); /** * 绑定服务时传递connection */ bindService(intent,mConnection, Context.BIND_AUTO_CREATE); } } }; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { /** * Binder 传递主要用的是stub * 通过Ibinder 获取 IBookManeager */ mRemoteBookManager = IBookManager.Stub.asInterface(service); try { // mRemoteBookManager = bookManager; List<Book> list = mRemoteBookManager.getBookList(); Log.e(TAG,"query book list,list type :"+list.getClass().getCanonicalName()); Log.e(TAG,"query book list:" + list.toString()); /** * 图书添加 */ Book newBook = new Book(3,"Android开发艺术探索"); mRemoteBookManager.addBook(newBook); Log.e(TAG,"add book:"+newBook.toString()); List<Book> list1 = mRemoteBookManager.getBookList(); Log.e(TAG,"new bookList:"+list1.toString()); mRemoteBookManager.registerListener(mOnNewBookArrivedListener); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { mRemoteBookManager = null; Log.e(TAG,"binder died."); } }; /** * 数据改变时的接口实现 */ private IOnNewBookArrivedListener mOnNewBookArrivedListener = new IOnNewBookArrivedListener.Stub(){ @Override public void onNewBookArrived(Book book) throws RemoteException { mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED,book).sendToTarget(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_book_maneger_aidl); Intent intent = new Intent(this, BookManagerService.class); /** * 绑定服务时传递connection */ bindService(intent,mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { /** * 在页面销毁时注销监听 */ if(mRemoteBookManager!=null&&mRemoteBookManager.asBinder().isBinderAlive()){ Log.e(TAG,"unregister listener:"+mOnNewBookArrivedListener); try { mRemoteBookManager.unregisterListener(mOnNewBookArrivedListener); } catch (RemoteException e) { e.printStackTrace(); } } /** * 解绑 service */ unbindService(mConnection); super.onDestroy(); } } Service端是另起一个进程的。这是一个跨进程添加查询书籍的例子 主要代码都加了注释。例子中使用观察者模式,监听书籍的添加操作。添加数据的接口是: import com.zrf.testaidl.testaidl.Book; interface IOnNewBookArrivedListener { void onNewBookArrived(in Book book); }