IPC

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,这时反序列化就会失败。

//手动添加serialVersion
private 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方式的优缺点

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值