• IPC机制1


    1、Android IPC简介

      Inter-Process Communication的缩写就是IPC,含义是进程间通信或是跨进程间通信,是指两个进程进行交换数据的过程。

    • 进程是什么?

      进程在pc上就是一个程序,在Android就是一个应用。线程表示的是cpu调度的最小单元,进程指一个执行单元。一个进程可包含多个线程,也可以只有一个线程。

      所以Android IPC就可以理解为不同应用间的通信,但一个应用也有多进程模式,所以IPC不仅是应用间的通信,不过这个没必要纠结,反正就是跨进程间通信。

    2、Android中的多进程模式

    • 开启多线程模式

      我们可以在AndroidManifest中修改Activity的属性,轻易的开启多线程模式。

    <activity
      android:name=".MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <activity
      android:name=".Main2Activity"
      android:process="com.xw.test" />
    <activity
      android:name=".Main3Activity"
      android:process=":test" />

      android:process指定这个属性就可以开启多进程模式,

      将三个Activity依次启动,然后使用adb shell可以看到

      这是MainActivity运行在这个应用的默认进程中,进程名就是包名

      这是Main2Activity运行在com.xw.test中

      这是Main3Activity运行在com.example.administrator.test:test中

      Main3Activity使用的“:”的含义是指要在当前的进程名之前附加上当前的包名。以“:”开头的进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一进程中,而不以“:”开头的进程属于全局进程,其他应用通过ShareUID方式可以和它跑在同一进程中。

      Android系统会为每一个应用分配一个唯一的UID,具有相同UID的应用才能共享数据,两个应用通过ShareUID方式可以跑在同一进程中还需要签名相同,在这种情况下它们可以互相访问对方的私有数据,比如data目录、组件信息等。

    •  多线程运行机制

      如果新建一个类,这个类中有一个public的静态成员变量,

    public class Data {
        public static int Id = 1;
    }

      然后我们在MainActivity的onCreate中将其赋值为2然后打印出来,然后我们再Main2Activity中直接打印出来。我们会发现原本应该是共享的静态变量,MainActivity修改为2打印也是2,Main2Activity打印还是1.

      其实,android会为每一个应用(或者说线程)分配一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,也就是说其实MainActivity和Main2Activity访问的但是两个名字相同的变量而已

      一般来说,多进程会造成如下几方面的问题:

      (1) 静态成员和单例模式失效:就上面的这种情况

      (2) 线程同步机制完全失效:已经不是一块内存了,所以无论是锁对象还是锁全局类都无法保证线程同步。

      (3)SharePreferences的可靠性下降:SharePreferences的底层是通过读/写XML文件出现的,并发写显然是会出问题的,甚至并发读/写都有可能出现问题。

      (4)Application会多次创建:当一个组件在跑一个新的进程的时候,分配独立的虚拟机,其实就是启动一个应用的过程,相当于系统把这个应用重启了一遍,就创建了新的Application。

    3、Binder

      Binder是Android中的一个类,它实现了IBinder接口,Binder是Android中的一种跨进程通信方式

      Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务和数据。

      这里使用AIDL来分析Binder的工作机制,

      先新建一个包并定义一个Book类,并实现Parcelable接口

    public class Book implements Parcelable {
    
        public int bookId;
        public String bookName;
    
        public Book(int bookId, String bokName){
            this.bookId = bookId;
            this.bookName = bookName;
        }
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        @Override
        public void writeToParcel(Parcel parcel, int i) {
            parcel.writeInt(bookId);
            parcel.writeString(bookName);
        }
    
        public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>(){
    
            @Override
            public Book createFromParcel(Parcel parcel) {
                return new Book(parcel);
            }
    
            @Override
            public Book[] newArray(int i) {
                return new Book[i];
            }
        };
    
        private Book(Parcel parcel){
            bookId = parcel.readInt();
            bookName = parcel.readString();
        }
    }
    View Code

      然后再创建Book.aidl和IBookManager.aidl

    //Book.aidl
    package com.xw.book.aidl;
    
    parcelable Book;
    
    //IBookManager.aidl
    package com.xw.book.aidl;
    
    import com.xw.book.aidl.Book;
    
    interface IBookManager{
        List<Book> getBookList();
        void addBook(in Book book);
    }

      Book.aidl是Book在AIDL中的声明,IBookManager.aidl是定义的一个接口。

      再点击安装到手机之后,在gen目录下的com.xw.book.aidl包中有一个IBookManager.java的类,这个是系统自动生成的

    /*
     * This file is auto-generated.  DO NOT MODIFY.
     * Original file: C:\Users\Administrator\Desktop\test\app\src\main\aidl\com\xw\book\aidl\IBookManager.aidl
     */
    package com.xw.book.aidl;
    public interface IBookManager extends android.os.IInterface
    {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.xw.book.aidl.IBookManager
    {
    private static final java.lang.String DESCRIPTOR = "com.xw.book.aidl.IBookManager";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
    this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.xw.book.aidl.IBookManager interface,
     * generating a proxy if needed.
     * 
     */
    public static com.xw.book.aidl.IBookManager asInterface(android.os.IBinder obj)
    {
    if ((obj==null)) {
    return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin!=null)&&(iin instanceof com.xw.book.aidl.IBookManager))) {
    return ((com.xw.book.aidl.IBookManager)iin);
    }
    return new com.xw.book.aidl.IBookManager.Stub.Proxy(obj);
    }
    @Override public android.os.IBinder asBinder()
    {
    return this;
    }
    
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
    switch (code)
    {
    case INTERFACE_TRANSACTION:
    {
    reply.writeString(DESCRIPTOR);
    return true;
    }
    case TRANSACTION_getBookList:
    {
    data.enforceInterface(DESCRIPTOR);
    java.util.List<com.xw.book.aidl.Book> _result = this.getBookList();
    reply.writeNoException();
    reply.writeTypedList(_result);
    return true;
    }
    case TRANSACTION_addBook:
    {
    data.enforceInterface(DESCRIPTOR);
    com.xw.book.aidl.Book _arg0;
    if ((0!=data.readInt())) {
    _arg0 = com.xw.book.aidl.Book.CREATOR.createFromParcel(data);
    }
    else {
    _arg0 = null;
    }
    this.addBook(_arg0);
    reply.writeNoException();
    return true;
    }
    }
    return super.onTransact(code, data, reply, flags);
    }
    private static class Proxy implements com.xw.book.aidl.IBookManager
    {
    private android.os.IBinder mRemote;
    Proxy(android.os.IBinder remote)
    {
    mRemote = remote;
    }
    @Override public android.os.IBinder asBinder()
    {
    return mRemote;
    }
    public java.lang.String getInterfaceDescriptor()
    {
    return DESCRIPTOR;
    }
    @Override public java.util.List<com.xw.book.aidl.Book> getBookList() throws android.os.RemoteException
    {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    java.util.List<com.xw.book.aidl.Book> _result;
    try {
    _data.writeInterfaceToken(DESCRIPTOR);
    mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
    _reply.readException();
    _result = _reply.createTypedArrayList(com.xw.book.aidl.Book.CREATOR);
    }
    finally {
    _reply.recycle();
    _data.recycle();
    }
    return _result;
    }
    @Override public void addBook(com.xw.book.aidl.Book book) throws android.os.RemoteException
    {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
    _data.writeInterfaceToken(DESCRIPTOR);
    if ((book!=null)) {
    _data.writeInt(1);
    book.writeToParcel(_data, 0);
    }
    else {
    _data.writeInt(0);
    }
    mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
    _reply.readException();
    }
    finally {
    _reply.recycle();
    _data.recycle();
    }
    }
    }
    static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }
    public java.util.List<com.xw.book.aidl.Book> getBookList() throws android.os.RemoteException;
    public void addBook(com.xw.book.aidl.Book book) throws android.os.RemoteException;
    }
    View Code
    • DESCRIPTOR

        Binder的唯一标识,一般使用当前Binderd的类名表示。

    • asInterface(android.os.IBinder obj)

        用于将服务端的Binder对象转换成客户端需要的AIDL接口类型的对象,这种转换是区分进程的,如果服务端和客户端位于同一进程,那么该方法会返回服务端的Stub对象本身,否则返回的是系统封装后的Stub.proxy对象。

    • onTransact

        这个方法运行在服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理, 服务端通过code可以确定客户端请求的目标方法是什么,从data中取出目标方法所需要的参数,然后执行目标方法没目标方法执行完后,就向reply中写入结果如果此方法返回false,那么客户端的请求就会失败

    • Proxy

        这个类中有两个方法分别是getBookList和addBook,两个方法的执行过程是一样的,说一个就行,方法将运行在客户端,先创建该方法所需要的输入型Parcel对象_data、输出型Parcel对象_reply,和返回值对象,然后把该方法的参数信息写入_data,然后调用transact方法来发起RPC(远程过程调用)请求;然后服务端的onTransact方法会被调用,知道RPC过程返回后,当前线程继续执行,并从_reply中取出RPC过程的返回结果,最后返回_reply中的结果

      以上就是Binder的工作机制,然后还有两点需要注意:当客户端发出请求的时候,由于当前线程会被挂起直至服务端进程返回数据,所以如果一个远程方法是很耗时的,那么不能在UI线程中发起此远程请求,其次,由于服务端的Binder方式运行在Binder的线程池中,所以Binder方法不管是否耗时都应该采用同步的方法去实现,因为它已经运行在一个线程中了。

      

    Binder的工作机制

      图片来源:http://blog.csdn.net/u012827296/article/details/51259006

     参考书籍:Android 开发艺术探索

  • 相关阅读:
    React学习笔记(六)事件处理
    React学习笔记(五)State&声明周期
    学会装逼,你的人生可能会开挂
    Go指南
    JavaScript检测数据类型
    $.on()方法和addEventListener改变this指向
    JavaScript返回上一页
    js继承
    js原型二
    全局变量与局部变量
  • 原文地址:https://www.cnblogs.com/xxbbtt/p/7977253.html
Copyright © 2020-2023  润新知