安卓的跨進(jìn)程通信IPC
Binder簡(jiǎn)介:
安卓系統(tǒng)基于Linux,但Binder是安卓獨(dú)有的跨進(jìn)程通信方式
- 從系統(tǒng)層來(lái)講Binder也是一個(gè)虛擬設(shè)備,驅(qū)動(dòng)在/dev/binder中扣草;
- 從framework層來(lái)講歌粥,binder是ServiceManager連接各種Manager(ActivityManager,WindowManger...)和ManagerService的橋梁蜂莉;
- 從應(yīng)用層來(lái)講音婶,Binder是客戶端和服務(wù)端通信的橋梁,客戶端可以通過(guò)服務(wù)端返回的Binder來(lái)調(diào)用服務(wù)端的各種實(shí)現(xiàn)钮孵。
2. Aidl實(shí)現(xiàn)梳理
通過(guò)aidl來(lái)了解Binder機(jī)制
- 為什么要設(shè)計(jì)AIDL語(yǔ)言强经?
- AIDL的語(yǔ)法是什么?
- 如何使用AIDL語(yǔ)言完成跨進(jìn)程通信掺涛?
- AIDL與Binder的區(qū)別是什么
- 綁定服務(wù)的幾種方式 BIND_AUTO_CREATE...
2.1 定義實(shí)體類 和 遠(yuǎn)程調(diào)用接口
Book.java類 實(shí)現(xiàn)Parcelable接口
public class Book implements Parcelable{
private long bookId;
private String bookName;
....
}
Book.aidl
package com.lxbinder.demo;
parcelable Book;
IBookInterface.aidl類
必須導(dǎo)入Book類 否則不能識(shí)別庭敦,Book類必須實(shí)現(xiàn)序列化接口
package com.lxbinder.demo;
import com.lxbinder.demo.Book;
interface IBookInterface {
void addBook(long bookId,String bookName);
List<Book> getBook();
}
2.2 實(shí)現(xiàn)Service端實(shí)現(xiàn)
public class BookService extends Service{
private ArrayList<Book> books = new ArrayList<>();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private IBookInterface.Stub mBinder = new IBookInterface.Stub() {
@Override
public void addBook(long bookId, String bookName) throws RemoteException {
books.add(new Book(bookId,bookName));
}
@Override
public List<Book> getBook() throws RemoteException {
return books;
}
};
}
2.3 實(shí)現(xiàn)客戶端調(diào)用
客戶端Activity實(shí)現(xiàn)ServiceConnection接口
需要注意的是:遠(yuǎn)程調(diào)用會(huì)掛起當(dāng)前線程,直到服務(wù)端返回?cái)?shù)據(jù)時(shí)喚醒當(dāng)前進(jìn)程薪缆,所以要當(dāng)成耗時(shí)任務(wù)對(duì)待秧廉,本示例忽略
public MainActivity extends AppCompatActivity implements View.OnClickListener,ServiceConnection{
// asInterface :如果service為本地進(jìn)程,直接返回服務(wù)端的Stub對(duì)象本身拣帽,否則返回的是Stub.Proxy代理對(duì)象
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mBinder = IBookInterface.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
unbindService(this);
mBinder = null;
}
// 綁定服務(wù)
private void startBind(){
Intent intent = new Intent(this,BookService.class);
this.bindService(intent,this, Context.BIND_AUTO_CREATE);
}
// 從服務(wù)端獲取 圖書列表 并在本地客戶端打印
private void printbooks(){
if(mBinder!=null){
try{
List<Book> books = mBinder.getBook();
StringBuilder sb = new StringBuilder();
for(int i = 0 ;i< books.size();i++){
sb.append("索引:"+i+" bookId: "+books.get(i).getBookId()+" 書名 "+books.get(i).getBookName()+"\n");
}
bookShowTv.setText(sb.toString());
}catch (Exception e){
e.printStackTrace();
}
}
}
private void addBook(){
if(mBinder!=null){
try{
mBinder.addBook(bookIdIndex++,"圖書"+bookIdIndex);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
2.4 接口aidl具體實(shí)現(xiàn)類的關(guān)鍵方法解析
android studio 為我們自動(dòng)生成IBookInterface.aidl的實(shí)現(xiàn)類
分析如下
靜態(tài)方法asInterface,區(qū)分是否當(dāng)前進(jìn)程疼电,分別返回具體的Stub對(duì)象還是Stub.Proxy對(duì)象
public static com.lxbinder.demo.IBookInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.lxbinder.demo.IBookInterface))) {
return ((com.lxbinder.demo.IBookInterface)iin);
}
return new com.lxbinder.demo.IBookInterface.Stub.Proxy(obj);
}
3. 手動(dòng)模仿AIDL實(shí)現(xiàn)
關(guān)鍵類實(shí)現(xiàn)
- IUserAIDL 客戶端服務(wù)端通信 接口定義
- UserStub (Binder)
- UserProxy (接口實(shí)現(xiàn))
1.IUSerAIDL
interface IUserAIDL extends android.os.IInterface{
final String DESCRIPTOR = "com.lxbinder.demo.IUserAIDL";
int TRANSACTION_addUser = 0;
int TRANSACTION_getUserList = 1;
void addUser(long userId,String userName) throws RemoteException;
List<User> getUserList() throws RemoteException;
}
- UserProxy
public class UserProxy implements IUserAIDL {
private IBinder mRemote;
UserProxy(IBinder remote)
{
mRemote = remote;
}
@Override
public IBinder asBinder(){
return null;
}
@Override
public void addUser(long userId,String userName) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(DESCRIPTOR);
data.writeLong(userId);
data.writeString(userName);
mRemote.transact(IUserAIDL.TRANSACTION_addUser, data, reply, 0);
reply.readException();
}
finally {
reply.recycle();
data.recycle();
}
}
@Override
public List<User> getUserList() throws RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<User> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(TRANSACTION_getUserList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(User.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
UserStub
abstract class UserStub extends Binder implements IUserAIDL {
public UserStub(){
this.attachInterface(this,DESCRIPTOR);
}
@Override
public IBinder asBinder(){
return this;
}
public static IUserAIDL asInterface(IBinder obj){
if(obj == null){
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if(iin!=null && (iin instanceof IUserAIDL)){
return (IUserAIDL)iin;
}
return new UserProxy(obj);
}
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case TRANSACTION_addUser:
data.enforceInterface(DESCRIPTOR);
long userId = data.readLong();
String name = data.readString();
reply.writeNoException();
addUser(userId,name);
return true;
case TRANSACTION_getUserList:
data.enforceInterface(DESCRIPTOR);
java.util.List<User> _result = this.getUserList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
default:
break;
}
return super.onTransact(code, data, reply, flags);
}
}