Binder機制(三)-代碼實現 一、Binder通信實現 二、AIDL 實現 三、Messenger 實現 AIDL

Android知識總結

一、Binder通信實現

1.1、model類

public class Person implements Parcelable {

    private String name;
    private int grade;

    public Person(String name, int grade) {
        this.name = name;
        this.grade = grade;
    }

    protected Person(Parcel in) {
        this.name = in.readString();
        this.grade = in.readInt();
    }

    public static final Creator<Person> CREATOR = new Creator<Person>() {
        @Override
        public Person createFromParcel(Parcel in) {
            return new Person(in);
        }

        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(grade);
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", grade=" + grade +
                '}';
    }
}

1.2、接口類

public interface IPersonManager extends IInterface {

    void addPerson(Person person) throws RemoteException;

    List<Person> getPersonList() throws RemoteException;
}

1.3、Proxy 類

Proxy 用於客戶端的實現

public class Proxy implements IPersonManager {
    //IPersonManager 的描述符
    private static final String DESCRIPTOR = "com.enjoy.binder.common.IPersonManager";

    private IBinder mRemote;

    public Proxy(IBinder remote) {
        mRemote = remote;
    }

    @Override
    public void addPerson(Person person) throws RemoteException {
        //用於client向service中寫入數據,打包成data
        Parcel data = Parcel.obtain();
        //用於client從service中讀取數據,打包成reply
        Parcel reply = Parcel.obtain();
        try {
            //檢測
            data.writeInterfaceToken(DESCRIPTOR);
            if ((person != null)) {
                //不爲空時寫入標識符1,用來service判定是否爲空數據,從而序列化數據
                data.writeInt(1);
                //把person寫入到 Parcel 中,就是序列化
                person.writeToParcel(data, 0);
            } else {
                //標識符爲0時,爲空數據
                data.writeInt(0);
            }
            Log.e("leo", "Proxy,addPerson: " + Thread.currentThread());
            //用 transact 向 service 發出命令,用於跨進程,client 掛起(同步的情況)
            mRemote.transact(Stub.TRANSACTION_addPerson, data, reply, 0);
            reply.readException();
        } finally {
            reply.recycle();
            data.recycle();
        }
    }

    @Override
    public List<Person> getPersonList() throws RemoteException {
        //用於向service中寫入數據
        Parcel data = Parcel.obtain();
        //用於client從service中讀取數據
        Parcel reply = Parcel.obtain();
        List<Person> result;
        try {
            data.writeInterfaceToken(DESCRIPTOR);
            //用 transact 向 service 發出命令,用於跨進程,client 掛起
            mRemote.transact(Stub.TRANSACTION_getPersonList, data, reply, 0);
            reply.readException();
            //獲取數據,從service中獲取
            result = reply.createTypedArrayList(Person.CREATOR);
        } finally {
            reply.recycle();
            data.recycle();
        }
        return result;
    }

    @Override
    public IBinder asBinder() {
        return mRemote;
    }
}

1.4、Stub 類

Stub 用於服務端的實現,必須繼承 Binder

public abstract class Stub extends Binder implements IPersonManager {

    private static final String DESCRIPTOR = "com.enjoy.binder.common.IPersonManager";
     //向binder中注入描述符
    public Stub() {
        this.attachInterface(this, DESCRIPTOR);
    }

    /**
     * 判斷是同一個進程還是跨進程
     *
     * @param binder
     * @return
     */
    public static IPersonManager asInterface(IBinder binder) {
        if ((binder == null)) {
            return null;
        }
        //如果是跨進程返回爲 null
        IInterface iin = binder.queryLocalInterface(DESCRIPTOR);
        //同一個進程
        if ((iin != null) && (iin instanceof IPersonManager)) {
            return (IPersonManager) iin;
        }
        //跨進程
        return new Proxy(binder);
    }

    @Override
    public IBinder asBinder() {
        return this;
    }

    /**
     * 接收client發出的命令
     *
     * @param code  標識符
     * @param data
     * @param reply
     * @param flags
     * @return
     * @throws RemoteException
     */
    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code) {
            case INTERFACE_TRANSACTION:
                //
                reply.writeString(DESCRIPTOR);
                return true;

            case TRANSACTION_addPerson:
                Log.e("leo", "Stub,TRANSACTION_addPerson: " + Thread.currentThread());
                //執行這個描述符的服務
                data.enforceInterface(DESCRIPTOR);
                Person arg0 = null;
                //不爲0時寫於數據
                if ((0 != data.readInt())) {
                    //從Parcel中讀取數據,就是反序列化
                    arg0 = Person.CREATOR.createFromParcel(data);
                }
                this.addPerson(arg0);
                reply.writeNoException();
                return true;

            case TRANSACTION_getPersonList:
                data.enforceInterface(DESCRIPTOR);
                //this 指的是 RemoteService 服務
                List<Person> result = this.getPersonList();
                reply.writeNoException();
                //向client返回結果
                reply.writeTypedList(result);
                return true;
        }
        return super.onTransact(code, data, reply, flags);
    }

    //client 和 service 之間的標識
    static final int TRANSACTION_addPerson = IBinder.FIRST_CALL_TRANSACTION;
    static final int TRANSACTION_getPersonList = IBinder.FIRST_CALL_TRANSACTION + 1;
}

1.5、Service 端

public class RemoteService extends Service {

    private ArrayList<Person> persons;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        persons = new ArrayList<>();
        Log.e("LeoAidlService", "success onBind");
        return iBinder;
    }

    private IBinder iBinder = new Stub() {
        @Override
        public void addPerson(Person person) throws RemoteException {
            persons.add(person);
        }

        @Override
        public List<Person> getPersonList() throws RemoteException {
            return persons;
        }
    };
}

1.6、client 實現類

public class ClientActivity extends AppCompatActivity {

    private IPersonManager iPersonManager;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this, RemoteService.class);
        intent.setAction("com.enjoy.binder");
        bindService(intent, connection, Context.BIND_AUTO_CREATE);

        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Log.e("leo", "------------onClick:" + Thread.currentThread());
                    iPersonManager.addPerson(new Person("leo", 3));
                    List<Person> persons = iPersonManager.getPersonList();
                    Log.e("leo", persons.toString() + "," + Thread.currentThread());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e("leo", "onServiceConnected: success");
            iPersonManager = Stub.asInterface(service);// proxy
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e("leo", "onServiceDisconnected: success");
            iPersonManager = null;
        }
    };
}

1.7、AndroidManifest.xml

        <activity android:name=".client.ClientActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".server.RemoteService"
            android:exported="true"
            android:process=":remote">
            <intent-filter>
                <action android:name="com.enjoy.binder" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>

二、AIDL 實現

2.1、支持的數據類型

  • 1、Java 的基本數據類型
  • 2、List 和 Map
    1)、元素必須是 AIDL 支持的數據類型
    2)、Server 端具體的類裏則必須是 ArrayList 或者 HashMap
  • 3、其他 AIDL 生成的接口
  • 4、實現 Parcelable 的實體

2.2、AIDL 編寫

AIDL 的編寫主要爲以下三部分:

  • 1、創建 AIDL
    1)、創建要操作的實體類,實現 Parcelable 接口,以便序列化/反序列化
    2)、新建 aidl 文件夾,在其中創建接口 aidl 文件以及實體類的映射 aidl 文件
    3)、Make project ,生成 Binder 的 Java 文件
   // Person.aidl  實體類的映射 aidl 文件
    package net.sxkeji.shixinandroiddemo2.bean;

    //還要和聲明的實體類在一個包裏
    parcelable Person;
    // IMyAidl.aidl  接口 aidl 文件
    package net.sxkeji.shixinandroiddemo2;

    // Declare any non-default types here with import statements
    import net.sxkeji.shixinandroiddemo2.bean.Person;

    interface IMyAidl {
       /**
         * 除了基本數據類型,其他類型的參數都需要標上方向類型:in(輸入), out(輸出), inout(輸入輸出)
         */
        void addPerson(in Person person);
  
        List<Person> getPersonList();
    }
  • 2、服務端
    1)、創建 Service,在其中創建上面生成的 Binder 對象實例,實現接口定義的方法
    2)、在 onBind() 中返回

public class PersonService extends Service {
    private static final String TAG = "PersonService";
    private CopyOnWriteArrayList<Person> mPerson;
 
    private Binder mBinder = new IPersonService.Stub() {
        @Override
        public List<Person> getPersonList() throws RemoteException {
            return mPerson;
        }
 
        @Override
        public void addPerson(Person person) throws RemoteException {
            mPerson.add(person);
        }
    };
 
    @Override
    public void onCreate() {
        super.onCreate();
        init();
    }
 
    private void init() {
        mPerson = new CopyOnWriteArrayList<>();
    }
 
 
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}
  • 3、客戶端
    1)、實現 ServiceConnection 接口,在其中拿到 AIDL 類
    2)、bindService()
    3)、調用 AIDL 類中定義好的操作請求
    private IPersonService mPersonService;
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mPersonService = IPersonService.Stub.asInterface(service);
            if (mPersonService == null) {
                Log.i(TAG, "mPersonService == null");
                return;
            }
        }
 
        @Override
        public void onServiceDisconnected(ComponentName name) {
 
        }
    };
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       
        Intent intent = new Intent(this, PersonService.class);
        intent.setPackage(PKG_NAME);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

三、Messenger 實現 AIDL

3.1、簡介

Messenger它是一種輕量級的IPC 方法,我們使用起來也是非常的簡單。他是使用Handler對AIDL進行了一次封裝,一次只能處理一個請求。並且Messenger在發送Message的時候不能使用他的obj字段,我們可以用bundle來代替。最後還有一點就是Messenger只是在客戶端與服務端跨進程的傳遞數據,而不能夠去訪問服務端的方法。

Messenger的使用步驟:
  其實對於Messenger用起來是非常簡單的,那麼我們首先來看一下這個Messenger的使用步驟:
  1. 在服務端我們實現一個 Handler,接收來自客戶端的每個調用的回調
  2. 這個Handler 用於創建 Messenger 對象(也就是對 Handler 的引用)

3. 用Messenger 創建一個 IBinder,服務端通過 onBind() 使其返回客戶端
  4. 客戶端使用 IBinder 將 Messenger(引用服務的 Handler)實例化,然後使用後者將 Message 對象發送給服務端
  5. 服務端在其 Handler 中(具體地講,是在 handleMessage() 方法中)接收每個 Message

3.2、service端

public class HandlerService extends Service {
    public static final int MESSAGE_TAG_1 = 1;
    public static final int MESSAGE_TAG_2 = MESSAGE_TAG_1 + 1;
    public static final int MESSAGE_TAG_3 = MESSAGE_TAG_2 + 1;

    private Messenger serviceMessage = new Messenger(new BinderHandler());
    public HandlerService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return serviceMessage.getBinder();
    }

    private class BinderHandler extends Handler{
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            Bundle data = msg.getData();
            if(null == data){
                return;
            }
            switch (msg.what){
                case MESSAGE_TAG_1:
                    String message = data.getString("message");
                    Toast.makeText(HandlerService.this, message, Toast.LENGTH_LONG).show();
                    break;
                case MESSAGE_TAG_2:
                    String str = data.getString("data");
                    Toast.makeText(HandlerService.this, str, Toast.LENGTH_LONG).show();
                    Message toClient = Message.obtain();
                    toClient.what = MESSAGE_TAG_3;
                    toClient.arg1 = 11111;
                    try {
                        //向客戶端發送消息
                        msg.replyTo.send(toClient);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
            }
        }
    }
}

3.3、client端

 public class MainActivity extends AppCompatActivity { 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        
        Intent intent = new Intent(this, HandlerService.class);
        intent.setAction("com.example.myapplication.service");
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
 
        findViewById(R.id.click_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message message = Message.obtain();
                message.what = HandlerService.MESSAGE_TAG_2;
                Bundle bundle = new Bundle();
                bundle.putString("data", "發送消息");
                message.setData(bundle);
                message.replyTo = clientMessenger;
                try {
                    messenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                } 
            }
        });
    }
    
    private Messenger messenger = null;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            messenger = new Messenger(service);
            Message message = Message.obtain();
            message.what = HandlerService.MESSAGE_TAG_1;
            Bundle bundle = new Bundle();
            bundle.putString("message", "建立連接");
            message.setData(bundle);
            try {
                messenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        
        @Override
        public void onServiceDisconnected(ComponentName name) {
            messenger = null;
        }
    };

    //接受客戶端消息
    private Messenger clientMessenger = new Messenger(new Handler(Looper.getMainLooper()){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            if (msg.what == HandlerService.MESSAGE_TAG_3) {
                Toast.makeText(MainActivity.this, msg.arg1 + "", Toast.LENGTH_LONG).show();
            }
        }
    });

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(connection);
    }
}

客戶端綁定服務端,獲取遠程Messenger的binder對象。調用Messenger的send函數,就可以吧Message發送至服務端的Handler。

同時,如果需要服務端回調客戶端(往客戶端的Handler發消息),則可以在send的Message中設置replyTo,服務端就可以往客戶端發送消息了。

Messenger與 AIDL 比較:

  • 當您需要執行 IPC 時,爲您的接口使用 Messenger 要比使用 AIDL 實現更加簡單,因爲 Messenger 會將所有服務調用排入隊列,而純粹的 AIDL 接口會同時向服務發送多個請求,服務隨後必須應對多線程處理。
  • 對於大多數應用,服務不需要執行多線程處理,因此使用 Messenger 可讓服務一次處理一個調用。如果您的服務必須執行多線程處理,則應使用 AIDL 來定義接口

3.4、發送流程

調用Messenger#send方法發送消息:

    private final IMessenger mTarget;

    //構造函數
    public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }

    public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }

在**IMessenger.aidl #send **的方法:

oneway interface IMessenger {
    void send(in Message msg);
}

Handler.getIMessenger()返回的是一個IMessenger的binder對象,它的send方法將會調用Handler的sendMessage方法。

源碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章