关于IPC的一点愚见
来源:互联网 发布:js数组concat 编辑:程序博客网 时间:2024/06/05 01:06
IPC是Inter-Process-Communication的简写,就是指进程间通讯。
Linux的进程间通讯,不必多说,就是指管道,信号和跟踪,信号量,套字节,共享内存等。
在这里主要讨论的是Android开发中常用的IPC方案。
目前为止,我们常用的IPC方案有以下几种:
1.使用Bundle
2.使用文件共享
3.使用Messenger(信使)
4.AIDL
5.ContentProvider组件
6.socket套字节
7.Binder线程池
现在让我一点一点总结,但是不会像前几篇打开源码一点点说,这是个总结:
1.Bundle 这是每一个每一个初学者都会接触到的一个类:
我们写Activity的onCreate():
protected void onCreate(Bundle savedInstanceState)
当时我初学的时候,查了一下文档,上面的说法大概是Bundle是作用存储Activity里面的信息。
正如上面创建Activity一样,四大组件中的三大组件都支持Intent中传递Bundle数据。Bundle实现了Parcelable接口,所以它可以很轻松在不同的进程之间传递。
public final class Bundle extends BaseBundle implements Cloneable, Parcelable
前面也说过,Binder作为进程间的核心机制来说,就是使用序列化的Parcelable进行传递的。也是因此Bundle只支持基本类型,实现了Parcelable接口的类,或者说也实现了Serializable的数据类型,还有一些Android支持的特殊的对象啊。
有一个特殊场景需要注意一下:A进程要进行一个计算,并把计算完成后,这个结果要启动进程B的一个组件并把结果发给B进程的一个组件。可是这个结算结果不支持放入Bundle怎么办。
可以有一个解决方案:我们通过Intent启动B进程的Service,将数据传到B的Service进行计算,再让Service器启动B进程中真正要启动的目标组件。这样就避免了自己去做进程间通讯。
2.文件共享
这里面也包含了SharePreference的方案,其实就是我们学Java里面的用过的知识,BufferedRead和PrintWriter一起运用序列化写入一个约定的好文件,在通过反序列化读出来。要么就用Android封装好的SharePreference,去解析里面的内容。
3.使用信使也就是Messenger
Messenger是用AIDL实现的轻量化的IPC方案。
让我们粗略的看看下面的怎么样:
public final class Messenger implements Parcelable
首先,Messenger已经实现了序列化,为了进程间通讯做准备。
public Messenger(Handler target) { mTarget = target.getIMessenger(); } public IBinder getBinder() { return mTarget.asBinder(); } public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); }
很熟悉吧,就是之前分析过AIDL,将所有的工作丢到IMessenger这个Binder类中工作,并且实现进程间通讯。
由于Messenger一次只做一个请求,因此,我们不需要考虑线程同步问题。那么Messenger实现步骤分两步:实现服务端和客户端:
1)实现服务端进程创建一个Service来处理来自客户端的请求,接着在Service的onBind返回的Binder进行处理。(为了证明能够完成进程通信,请在AndroidManifest.xml注册Service增加一个属性android:process=”:remote”)
MessengerService.java
public class MessengerService extends Service{ private static String Tag = "Messenger"; private static class MessengerHandler extends Handler{ @Override public void handleMessage(Message msg){ switch (msg.what) { case 1: Log.e(Tag, "receive msg from Client:" + msg.getData().getString("msg")); Messenger client = msg.replyTo;//此处是当从客户端发送消息过来是后,声明的新Messenger Message replyMessage = Message.obtain(null,0); Bundle bundle = new Bundle();//Bundle作为数据传输的容器 bundle.putString("reply","received"); replyMessage.setData(bundle); try { client.send(replyMessage);//发送到客户端 } catch (RemoteException e) { // TODO: handle exception e.printStackTrace(); } break; default: super.handleMessage(msg); break; } } } private final Messenger messenger = new Messenger(new MessengerHandler()); @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return messenger.getBinder(); }
MainActivity.java
public class MainActivity extends Activity { private static final String TAG = "MessageActivity"; private Messenger mService; private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler()); @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); } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName arg0) { // TODO Auto-generated method stub } @Override public void onServiceConnected(ComponentName className, IBinder service) { // TODO Auto-generated method stub mService = new Messenger(service);//客户端发向服务端的数据 Message msg = Message.obtain(null,1);//1是message的what,标志位 Bundle data = new Bundle(); data.putString("msg", "hello,this is client"); msg.setData(data); msg.replyTo = mGetReplyMessenger;//对返回的Msg处理 try{ mService.send(msg);//客户端发送到服务端的数据 }catch(RemoteException e){ e.printStackTrace(); } } }; //此处是处理从服务器返回的数据 private static class MessengerHandler extends Handler{ @Override public void handleMessage(Message msg){ Log.e("handler", "handle"); switch (msg.what) { case 0: Log.e(TAG, "0"); Log.e(TAG, "receive msg from Service:" + msg.getData().getString("reply")); break; default: super.handleMessage(msg); break; } } } @Override protected void onDestroy(){ unbindService(mConnection); super.onDestroy(); }}
这里要注意,发送端发到接收端,那么接收端就必须有一个Handler来处理。一般的以客户端发向服务端的方向作为基准,要接受数据,客户端要有replyTo应答:msg.replyTo = Handler。服务端则是需要通过msg.replyTo来声明一个新的Messenger。
这样就能够完成进程间通讯。
以后空在慢慢研究Meesenger,整理出文章,现在只需要怎么用就行。
4.AIDL的使用:
AIDL的使用在前面说了一下,现在介绍怎么使用。
第一步:我们需要建立一个包,里面放的全是AIDL的文件以及AIDL相关的类。为什么这么做呢?这是因为我们要这个AIDL的文件放入客户端里面,来办到进程间通讯。如果不这么做,反序列和序列化的时候,Parcelable是根据包的结构做出像Serializable那样的序列码,如果包的结构不一样,序列会出现问题。
第二步:在这个包里面,创建aidl文件,在里面不是.java格式,因此我们只能手动的声明package,import类进来。注意在这里面,这能够处理基本数据类型,实现了Parcelable接口的类。
支持类型如下:
基本类型:int,long,char,boolean,double等
String,CharSequence;
List:支持ArrayList
Map:只支持HashMap
Parcelable:支持所有实现了Parcelable的接口
AIDL:AIDL本省也可以调用AIDL
这里我们做一个远程服务通知有新书的到来的一个过程
如下:
Book.aidl
package com.example.bindertest.aidl;parcelable Book;
IBookManager.aidl
package com.example.bindertest.aidl;import com.example.bindertest.aidl.Book;import com.example.bindertest.aidl.IOnNewBookArrived;interface IBookManager{ List<Book> getBookList(); void addBook(in Book book); void registerListener(IOnNewBookArrived listener); void unregisterListener(IOnNewBookArrived listener);}
IOnNewBookArrived.aidl
package com.example.bindertest.aidl;import com.example.bindertest.aidl.Book;import com.example.bindertest.aidl.IOnNewBookArrived;interface IBookManager{ List<Book> getBookList(); void addBook(in Book book); void registerListener(IOnNewBookArrived listener); void unregisterListener(IOnNewBookArrived listener);}
我们要做的目的,就是为了实现进程两端的相互的通信,因此,在Service端实现了功能为:返回书本的list,添加书本,绑定观察者,解绑观察者的Binder,将参数发送到另一端处理。
而在Activity中实现了一旦新书到达就发送的通知Binder,由于我们需要一个Handler来处理消息,因此这个Binder声明在客户端。此时在这个Binder中,那么相对于Service组件来说,Activity组件此时作为服务端,Service组件作为客户端。这个思想我发现在我研究四大组件的时候经常使用。
说明就这么多,下面是源码:
BookManager.java
public class BookManagerService extends Service{ private static final String TAG = "BMS"; /*作为线程同步时候的容器,线程写入的时候不会写入内存,而是写入副本**/ private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>(); /*判断Service是否存活的原子类**/ private AtomicBoolean mIsServiceDestroyed = new AtomicBoolean(false); /*IInterface的callback对象存入了真正的Binder对象,不然移除对象的时候,移除不干净**/ private RemoteCallbackList<IOnNewBookArrived> mListenerList = new RemoteCallbackList<IOnNewBookArrived>(); //调用AIDL中Stub抽象类,在Service中实现本地方法 private Binder mBinder = new IBookManager.Stub() { @Override public List<Book> getBookList() throws RemoteException { // TODO Auto-generated method stub return mBookList; } @Override public void addBook(Book book) throws RemoteException { // TODO Auto-generated method stub mBookList.add(book); } @Override public void registerListener(IOnNewBookArrived listener) throws RemoteException { // TODO Auto-generated method stub mListenerList.register(listener); } @Override public void unregisterListener(IOnNewBookArrived listener) throws RemoteException { // TODO Auto-generated method stub mListenerList.unregister(listener); } }; /*为了让我们的远程服务不让任何客户端连上,我们做一个permission权限的检查**/ @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub int check = checkCallingOrSelfPermission("com.example.bindertest.permission.ACCESS_BOOK_SERVICE"); if(check == PackageManager.PERMISSION_DENIED){ return null; } return mBinder; } @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(){ mIsServiceDestroyed.set(true); super.onDestroy(); } /*在这里我们从存了Binder的list中取出实例,这个list相当于观察者模式这通知后,被观察者做出相应的动作**/ private void onNewBookArrived(Book book)throws RemoteException{ mBookList.add(book); final int N = mListenerList.beginBroadcast(); for(int i=0;i<N;i++){ IOnNewBookArrived l = mListenerList.getBroadcastItem(i); if(l != null){ try{ /*这里调用调用另一端Notify通知方法**/ l.onNewBookArrived(book); }catch (RemoteException e) { // TODO: handle exception e.printStackTrace(); } } } mListenerList.finishBroadcast(); } /*启用线程,为的是每5秒模拟发送一个通知的情景**/ private class ServiceWorker implements Runnable{ @Override public void run() { // TODO Auto-generated method stub while(!mIsServiceDestroyed.get()){ try { Thread.sleep(5000); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } int bookid = mBookList.size()+1; Book newBook = new Book(bookid, "new book#"+bookid); try { onNewBookArrived(newBook); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } } }}
下面是MainActitivty.java
public class MainActivity extends Activity { private static final String TAG = "BookManagerActvity"; 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, "received a new book"+msg.obj); break; default: super.handleMessage(msg); break; } } }; //声明ServiceConnect用于绑定服务 private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName classname) { // TODO Auto-generated method stub } @Override public void onServiceConnected(ComponentName classname, IBinder service) { // TODO Auto-generated method stub //判断是本地还是远程的 IBookManager bookManager = IBookManager.Stub.asInterface(service); try{ List<Book> list = bookManager.getBookList(); Log.e(TAG, "query listType:"+list.getClass().getCanonicalName()); Log.e(TAG, "query list element:"+list.toString()); Book newbook = new Book(323, "a new book"); bookManager.addBook(newbook); List<Book> list2 = bookManager.getBookList(); Log.e(TAG, "query list2 element:"+list2.toString()); mRemoteBookManager = bookManager; Book book2 = new Book(3, "Android up"); mRemoteBookManager.addBook(book2); List<Book> list3=mRemoteBookManager.getBookList(); Log.e(TAG, "query list2 element:"+list3.toString()); bookManager.registerListener(listener);//绑定观察者监听器 }catch(RemoteException e){ e.printStackTrace(); } } }; /*在这里实现了加入观察者出现了变化,则发送一个Msg到Handler**/ private IOnNewBookArrived listener = new IOnNewBookArrived.Stub() { @Override public void onNewBookArrived(Book book) throws RemoteException { // TODO Auto-generated method stub mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED,book).sendToTarget(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(MainActivity.this,BookManagerService.class); bindService(intent, conn, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy(){ if((mRemoteBookManager != null)&&mRemoteBookManager.asBinder().isBinderAlive()){ try { Log.e(TAG, "unregister listener:"+listener); mRemoteBookManager.unregisterListener(listener);//解除监听器的绑定 } catch (RemoteException e) { // TODO: handle exception e.printStackTrace(); } } unbindService(conn); super.onDestroy(); }}
5.内容提供器
因为Sqlite不允许多进程的访问,ContentProvider做出了允许同步的方案。
具体一般人都会,这就略。
6.socket套字节
本地是通过端口来访问,单独开下一章来总结
7.Binder连接池
Binder连接池,其实就是使用aidl。为什么分开来说呢,主要是因为在需求中有可能会出现需要控制多个aidl,难道我们一个个去实现每一个函数,这明显不可能,我需要的是BinderPool这种策略。
单独开一章来总结。
- 关于IPC的一点愚见
- 关于AsyncTask的一点愚见
- 关于Activity的一点愚见
- 关于数模中编程的一点愚见
- 关于数模中编程的一点愚见
- 关于Android动画的一点愚见
- 关于activity启动流程的一点愚见
- 关于Notification通知的一点愚见(自定义通知栏)
- 关于Notification的一点愚见(PendingIntent工作流程)
- 关于RemoteView的一点愚见(实现桌面小部件)
- 关于list的愚见
- 关于动态数组的愚见
- 关于Scoket的一些愚见
- 对MVC、三层架构的一点愚见
- 关于滚动图片停在浏览器边界上的一点解决办法(个人愚见)。。
- 关于Binder在Java上工作的一点愚见(一)
- 关于Binder在Java上工作的一点愚见(二)
- 关于RemoteView的一点愚见(RemoteView在AppWidget中的工作流程)
- MyWidget MyLabel-- 重写 -- 双击/单击/移动/事件
- ReentrantReadWriteLock类和ReentrantLock类的区别
- List集合sort
- wegwe3g23
- es 学习 5 DSL mapping 使用 案例
- 关于IPC的一点愚见
- AndroidStudio安装配置详细过程
- 设计模式之观察者模式
- TS流分析
- leetcode_c++:树:Count Complete Tree Nodes(222 )
- JDK安装与环境变量配置
- 11 第一个特效 12灯泡开关案列 13 找对象 14操作对象
- java 发送邮件
- 用实例来理解IComparable和IComparer