一、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方法。