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对象。

Alt text

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方式的优缺点