IPC
来源:互联网 发布:淘宝客服月会总结 编辑:程序博客网 时间:2024/06/09 14:58
IPC简介
IPC是Inter-Process Communication的缩写,含义为进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程。
Android中的多进程模式
通过给四大组件指定android:process属性,可以轻易开启多进程模式。进程名以“:”开头的进程属于当前应用的私有进程;不以“:”开头的进程属于全局进程,其它应用通过ShareUID方式可以和它跑在同一个进程中。
我们知道Android系统会为每个应用分配唯一的UID,具有相同的UID的应用才能共享数据。而两个应用通过ShareUID跑在同一个全局进程是有要求的,需要两个应用有相同的ShareUID并且签名相同才可以,这时的两个应用,就像一个应用的两个部分。注意:UID跟ShareUID不一样。
多进程模式的运行机制
当一个应用开启了多进程模式,就相当于两个不同的应用采用了ShareUID模式。
IPC基础概念
Serializable接口
Serializable是Java所提供的一个序列化接口,为对象提供了标准的序列化和反序列化操作;序列化过程中会将数据先写进文件,反序列化时会读取文件数据,因此序列化和反序列化过程需要大量的I/O操作。
//序列化User user = new User(0,"jake",true);ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt"));out.writeObject(user);out.close();//反序列化ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt"));User user = (User)int.readObject();in.close();
注意:反序列化过程是有要求的,serialVersionUID必须一样才能反序列化成功。serialVersionUID的详细工作机制是这样的:序列化的时候系统会把当前类的serialVersionUID写入序列化的文件上中(也可以是其它中介),当反序列化的时候系统会检测文件中的serialVersionUID,看它是否和当前类的serialVersionUID一致,如果一致就说明序死化的类的版本和当前类的版本是相同的,这个时候可以成功反序列化。
一般来说,我们应该手动指定serialVersionUID的值,这样就可以避免反序列化失败;如果不手动指定serialVersionUID的值,当增加或删除某些成员变量时,系统就会重新计算当前类的hash值并把它赋值给serialVersionUID,这时反序列化就会失败。
//手动添加serialVersionprivate static final long serialVersionUID = 1L;
Parcelable接口
Parcelable是Android所提供的一个序列化接口,为对象提供了序列化、反序列化和内容描述,序列化和反序列化都只是将数据保存到内存中,因此效率高,大概是Serializable的10倍。
序列化由writeToParcel方法完成,最终是通过Parcel中的一系列write方法来完成;反序列化由CREATOR来完成,其内部标明了如何创建序列化对象和数组,并通过Parcel的一系列read方法来完成反序列化过程;内容描述由describeContents方法来完成,几乎所有情况下这个方法都应该返回0,仅当当前对象存在文件描述符时,此方法才返回1;当当前对象内存在另一个可序列化对象时,需要传递当前线程的上下文类加载器。
Intent
Intent是Parcelable的子类,因此它本身就可以在进程间传输,同时它也是一种进程间通信的桥梁,Intent的工作机制比较复杂,这里就不详细讲解了。
Bundle
Bundle是Parcelable的子类,因此Bundle也可以在进程间传输。
Serializable和Parcelable的选择:
一般情况下我们建议使用Parcelable,但在以下两种情况还是使用Serializable比较好:
1、需要将对象序列化后保存到存储设备;
2、需要将对象序列化后通过网络传输;
这两种情况使用Parcelable也是可以的,但使用起来会比较复杂,而Serializable本身就对数据做I/O操作,因此使用起来简单。
Binder
Binder比较特别,可以理解为一个虚拟的物理设备,它的设备驱动是/dev/binder,它主要为两个进程搭建数据通信的桥梁,是ServiceManager连接各种Manager和相应MessagerService的桥梁。
Android开发中,Binder主要用在Service中。
Android中的IPC方式
1、使用Bundle
Bundle实现了Parcelable接口,所以它可以方便地在不同的进程间传输。
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);Bundle bundle = new Bundle();bundle.putString("key","value");intent.putExtras(bundle);FirstActivity.startActivity(intent);
2、使用文件共享
两个进程通过读/写同一个文件来交换数据,比如A进程把数据写入文件,B进程通过读取这个文件来获取数据。由于Android系统基于Linux,使得其并发读/写文件可以没有限制地进行。所以如果并发读/写,那么我们读出来的内容有可能不是最新的。SharedPreferences是个特例,系统对它的读/写有一定的缓存策略,即在内存中会有一份SharePreferences文件的缓存,因此在多进程模式下,系统对它的读/写变得不可靠,因此,不建议在进程间通信中使用SharedPreferences。
MyConstants.java
public static final String CHAPTER_PATH = Environment.getExternalStorageDirectory() + File.separator + "cache";public static final String CACHE_FILE_PATH = CHAPTER_PATH + File.separator + "cache.xml";
FirstActivity.java
//A进程中的FirstActivity:写入数据到文件private void persistToFile(){ new Thread(new Runnable(){ @Override public void run(){ User user = new User(1,"hello",false); File dir = new File(MyConstants.CHAPTER_PATH); if(!dir.exists()){ dir.mkdirs(); ) File cachedFile = new File(MyConstants.CACHE_FILE_PATH); ObjectOutputStream objectOutputStream = null; try{ objectOutputStream = new ObjectOutputStream(new FileOutputStream(cacheFile)); objectOutputStream.writeObject(user); }catch(IOException e){ e.printStackTrace(); }finally{ if(objectOutputStream != null){ objectOutputStream.close(); } } } }).start();}
SecondActivity.java
//B进程中的BecondActivity:读文件数据private void ercoverFromFile(){ new Thread(new Runnable(){ @Override public void run(){ User user = null; File cachedFile = new File(MyConstants.CACHE_FILE_PATH); if(cachedFile.exists()){ ObjectInputStream objectInputStream = null; try{ objectInputStream = new ObjectInputStream(new FileInputStream(cachedFile)); user = (User)objectInputStream.readObject(); }catch(IOException e){ e.printStackTrace(); }catch(ClassNotFoundException e){ e.printStackTrace(); }finally{ if(objectInputStream != null){ objectInputStream.close(); } } } } }).start();)
使用3、Messenger
Messenger是一种轻量级的IPC方案,它的底层实现是AIDL。通过它可以在不同的进程中传递Message对象。
MyConstants.java
public static final CLIENT_MSG_KEY = "client_msg";public static final SERVICE_MSG_KEY = "service_msg";public static final int MSG_FROM_CLIENT = 1;public static final int MSG_FORM_SERVICE = 2;
客户端:
public class MessengerActivity extends Activity { private Messenger mService; private static class MessengerHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MyConstants.MSG_FORM_SERVICE: //接收服务端传来的数据 String message = msg.getData().getString(MyConstants.SERVICE_MSG_KEY); break; default: super.handleMessage(msg); break; } } } private final Messenger mMessenger = new Messenger(new MessengerHandler()); private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //与服务端连接成功后,获取服务端的Messenger mService = new Messenger(service); //通过服务端的Messenger将数据和客户端的Messenger传递给服务端 Message msg = Message.obtain(null, MyConstants.MSG_FROM_CLIENT); Bundle data = new Bundle(); data.putString(MyConstants.MSG_KEY, "hello"); msg.setData(data); msg.replyTo = mMessenger; try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = new Intent(this, MessengerService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { unbindService(mConnection); super.onDestroy(); }}
服务端:MessengerService.java
public class MessengerService extends Service {private static class MessengerHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MyConstants.MSG_FROM_CLIENT: //接收客户端传来的数据 String message = msg.getData().getString(MyConstants.CLIENT_MSG_KEY); //获取客户端的Messenger,并将数据传递给客户端 Messenger client = msg.replyTo; Message relpyMessage = Message.obtain(null, MyConstants.MSG_FORM_SERVICE); Bundle bundle = new Bundle(); bundle.putString(MyConstants.SERVICE_MSG_KEY,"welcome"); relpyMessage.setData(bundle); try { client.send(relpyMessage); } catch (RemoteException e) { e.printStackTrace(); } break; default: super.handleMessage(msg); break; } } } private final Messenger mMessenger = new Messenger(new MessengerHandler()); @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); }}
4、使用AIDL
Book.java
public class Book implements Parcelable{ public int bookId; public String bookName; public Book(int bookId,String bookName){ this.bookId = bookId; this.bookName = bookName; } ......}
Book.aidl
parcelable Book;
IOnNewBookArrivedListener.aidl
interface IOnNewBookArrivedListener{ void onNewBookArrived(in Book book);}
IBookManager.aidl
interface IBookManager{ List<Book> getBookList(); void addBook(in Book book); void registerListener(IOnNewBookArrivedListener listener); void unregisterList(IOnNewBookArrivedListener listener);}
客户端:BookManagerActivity.java
BookManagerActivity extents Activity{ private IBookManager mBookManager; private IOnNewBookArrivedListener mOnNewBookArrivedListener = new IOnNewBookArrivedListener.Stub(){ @Override public void onNewBookArrived(Book newBook) throws RemoteException{ //当服务端有数据更新时,会回调这个方法 //接收服务端的数据 } } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //连接成功后,获取服务端的IBookManager mBookManager = IBookManager.Stub.asInterface(service); //调用aidl方法,主动获取服务端的数据 List<Book> bookList = mBookManager.getBookList(); //注册 mBookManager.registerListener(mOnNewBookArrivedListener); } @Override public void onServiceDisconnected(ComponentName name) { mBookManager = null; } } }; @Override protected void onCreate(Bundle saveInstanceState){ Intent intent = new Intent(this,BookManagerService.class); bindService(intent,mConnection,Context.BIND_AUTO_CREATE); } @Override void onDestroy(){ if(mBookManager != null && mBookManager.asBinder().isBinderAlive()){ try{ mBookManager.unregisterListener(mOnNewBookArrivedListener); }catch(RemoteException e){ e.printStackTrace(); } } unnindService(mConnection); super.onDestroy(); }}
服务端:BookManagerService.java
public class BookManagerService extends Service{ private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>(); private RemoteCallbackList<IOnNewBookArrivedListener> mListenerList = new RemoteCallbackList(); //实现AIDL里的方法 private Binder mBinder = 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){ mListenerList.register(listener); } @Override public void unregisterList(IOnNewBookArrivedListener listener){ mListenerList.unregister(); } } @Override public void onCreate(){ super.onCreate(); //初始化数据,并通知有消息更新 onNewBookArrived(new Book(1,"Android")); } @Override public IBinder onBind(Intent intent){ return mBinder; } /** * 通知消息变化 */ private void onNewBookArrived(Book book) throws RemoteException{ mBookList.add(book); final int N = mListenerList.beginBroadcast(); for(int i = 0 ; i < N ; i++){ IOnNewBookArrivedListener listener = mListenerList.getBroadcastItem(i); if(listener != null){ try{ listener.onNewBookArrived(book); }catch(RemoteException e){ e.printStackTrace(); } } } mListenerList.finishBroadcast(); } }
5、使用ContentProvider(内容提供者)
ContentProvider是Android中提供的专门用于不同应用间进行数据共享的方式。
android:authorities是ContentProvider的唯一标识,通过这个属性外部应用就可以访问我们的BookProvider,
因此,android:authorities必须是唯一的,建议在命名的时候加上包名作为前缀。
服务端:BookContentProvide.java
public class BookContentProvide extends ContentProvider { @Override public boolean onCreate() { return false; } @Nullable @Override public String getType(@NonNull Uri uri) { //用来返回一个Uri请求所对应的MIME类型(媒体类型),比如图片、视频等,这个媒体类型还是有点复杂的, // 如果我们的应用不关注这个选项,可以直接在这个方法中返回null或者“*/*” return null; } @Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) { //增 return null; } @Override public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) { //删 return 0; } @Override public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) { //改 return 0; } @Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) { //查 return null; }}
客户端:
Uri uri = Uri.parse("Content://" + authorities); //authorities是ContentProvider的android:authorities属性值context.getContentResolver().query(uri, null, null, null, null);
6、使用Socket(套接字)
Socket是网络通信中的概念,它分为流式套接字和用户数据报套接字,分别对应于网络的传输控制层中的TPC和UDP协议。
TPC协议是面向连接的协议,提供稳定的双向通信功能,TPC连接的建立需要经过“三次握手”才能完成,为了提供稳定的数据传输功能,其本身提供了超时重传机制,因此具有很高的稳定性;
UDP是无连接的,提供不稳定的单向通信功能,UDP也可以实现双向通信功能。在性能上,UDP具有更好的效率,其缺点是不保证数据一定能正确传输,尤其是在网络阻塞的情况下
Binder连接池
各种IPC方式的优缺点
- IPC
- ipc$
- ipc$
- ipc$
- ipc$
- IPC
- IPC$
- IPC$
- IPC
- IPC
- IPC
- IPC
- IPC
- IPC
- IPC
- ipc
- IPC
- IPC
- zencart添加自定义页面 about_us等等
- 29.2Httpclient和Spring的整合
- Linux与Windows的不同
- VMware简介
- Linux分区与格式化
- IPC
- android.view.InflateException: Binary XML file line #1: Error inflating class
- Tensorflow实战学习(四十五)【人工智能,深度学习,TensorFlow,比赛,公司】
- quartz时间配置
- Linux基本命令简介
- Go使用grpc+http打造高性能微服务
- scala-包
- day3_spring04_jdbcTemplate实现crud操作(修改和删除操作)
- 分区之分区设备文件名及挂载