Messenger是以串行的方式处理客户端发来的消息;
如果大量消息同时发送到服务端,服务端仍然只能一个个处理;
如果有大量的并发请求,用Messenger就不合适了;
Messenger主要作用是传递消息,有时候我们需要跨进程调用服务端的方法;
这就需要AIDL来实现跨进程调用服务端的方法;
1、服务端
创建一个Service来监听服务端的连接请求;
创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明;
最后在Service中实现这个AIDL接口;
2、客户端
首先需要绑定服务端的Service,绑定成功之后,将服务端返回的Binder对象转成AIDL接口所属的类型;
接着就可以调用AIDL中的方法了;
3、AIDL接口的创建
为了方便AIDL的开发,建议把所有和AIDL相关的类和文件全部放入同一个包中;
这样做的好处是:当客户端要用时,可以直接把整个包复制到客户端工程中;
1 package com.example.aidltest_server; 2 3 import android.os.Parcel; 4 import android.os.Parcelable; 5 6 public class Book implements Parcelable { 7 private String name; 8 9 public Book(String name){ 10 this.name = name; 11 } 12 13 public String getName(){ 14 return name; 15 } 16 17 public void setName(String name){ 18 this.name = name; 19 } 20 21 @Override 22 public String toString(){ 23 return "book name: "+name; 24 } 25 26 @Override 27 public int describeContents(){ 28 return 0; 29 } 30 31 @Override 32 public void writeToParcel(Parcel dest,int flags){ 33 dest.writeString(this.name); 34 } 35 36 public void readFromParcel(Parcel dest){ 37 name = dest.readString(); 38 } 39 40 protected Book(Parcel in){ 41 this.name = in.readString(); 42 } 43 44 public static final Creator<Book> CREATOR = new Creator<Book>() { 45 @Override 46 public Book createFromParcel(Parcel source) { 47 return new Book(source); 48 } 49 50 @Override 51 public Book[] newArray(int size) { 52 return new Book[size]; 53 } 54 }; 55 }
AIDL经常要用到Parcelable对象,除了定义一个类,比如Book类去实现Parcelable接口之外;
还需要创建一个和它同名的AIDL文件,并在其中声明为Parcelable类型;如上面所示;
服务端还要声明一个BookController.aidl
其具体实现放在了Service中;
1 // BookController.aidl 2 package com.example.aidltest_server; 3 import com.example.aidltest_server.Book; 4 import com.example.aidltest_server.AIDLCallBack; 5 // Declare any non-default types here with import statements 6 7 interface BookController { 8 List<Book> getBookList(); 9 void addBookInOut(inout Book book); 10 void registerCallback(in AIDLCallBack cb); 11 void unregisterCallBack(in AIDLCallBack cb); 12 }
AIDLCallBack.aidl
这个是客户端提供给服务端的回调接口,在服务端中声明,但其具体实现由客户端提供;
// AIDLCallBack.aidl package com.example.aidltest_server; // Declare any non-default types here with import statements interface AIDLCallBack { void OnReply(); }
4、服务端的实现
1 package com.example.aidltest_server; 2 3 import android.app.Service; 4 import android.content.Intent; 5 import android.os.IBinder; 6 import android.os.RemoteCallbackList; 7 import android.os.RemoteException; 8 import android.util.Log; 9 10 import java.util.ArrayList; 11 import java.util.List; 12 13 public class AIDLService extends Service { 14 15 private static final String TAG = "Server"; 16 private static final String SERVICE_ACTION = "com.example.aidltest_server.AIDLTEST"; 17 private List<Book> bookList; 18 //远程回调函数注册机制,首先定义一个回调函数列表; 19 private RemoteCallbackList<AIDLCallBack> mCallBackList = new RemoteCallbackList<>(); 20 21 public AIDLService() { 22 Log.d(TAG, "AIDLService: "); 23 } 24 25 @Override 26 public void onCreate(){ 27 super.onCreate(); 28 Log.d(TAG, "onCreate: "); 29 bookList = new ArrayList<>(); 30 initData(); 31 } 32 33 @Override 34 public IBinder onBind(Intent intent) { //一旦服务端和客户端建立连接,返回BookController AIDL的实现类stub 35 Log.d(TAG, "onBind: "); 36 if(intent.getAction().equals(SERVICE_ACTION )){ 37 Log.d(TAG, "onBind Return ibinder: "); 38 return stub; 39 } 40 Log.d(TAG, "onBind Return null: "); 41 return null; 42 } 43 44 @Override 45 public void onDestroy(){ 46 Log.d(TAG, "onDestroy: "); 47 } 48 49 private void initData(){ 50 Book book1 = new Book("或者"); 51 Book book2 = new Book("活着"); 52 Book book3 = new Book("火者"); 53 bookList.add(book1); 54 bookList.add(book2); 55 bookList.add(book3); 56 } 57 58 private final BookController.Stub stub = new BookController.Stub() { //这里是AIDL接口的实现 59 @Override 60 public List<Book> getBookList() throws RemoteException{ 61 return bookList; 62 } 63 64 @Override 65 public void addBookInOut(Book book) throws RemoteException{ 66 if(book != null){ 67 bookList.add(book); 68 sendResponse(); 69 } 70 else 71 { 72 Log.e(TAG,"接收到空对象"); 73 } 74 } 75 76 @Override 77 public void registerCallback(AIDLCallBack cb){ //客户端会调用该接口注册回调函数 78 if(cb != null){ 79 mCallBackList.register(cb); 80 } 81 } 82 83 @Override 84 public void unregisterCallBack(AIDLCallBack cb){ //客户端调用该接口去注册回调函数 85 if(cb != null){ 86 mCallBackList.unregister(cb); 87 } 88 } 89 }; 90 91 private void sendResponse(){ //服务端调用回调函数的封装函数 92 int len = mCallBackList.beginBroadcast(); 93 for(int i = 0; i<len; i++){ 94 try{ 95 mCallBackList.getBroadcastItem(i).OnReply(); 96 }catch(RemoteException e){ 97 e.printStackTrace(); 98 } 99 } 100 mCallBackList.finishBroadcast(); 101 } 102 }
5、客户端的实现
1 package com.example.aidltest_client; 2 3 import androidx.appcompat.app.AppCompatActivity; 4 5 import android.content.ComponentName; 6 import android.content.Context; 7 import android.content.Intent; 8 import android.content.ServiceConnection; 9 import android.os.Bundle; 10 import android.os.IBinder; 11 import android.os.RemoteException; 12 import android.util.Log; 13 import android.view.View; 14 15 import com.example.aidltest_server.AIDLCallBack; 16 import com.example.aidltest_server.Book; 17 import com.example.aidltest_server.BookController; 18 19 import java.util.List; 20 21 public class MainActivity extends AppCompatActivity { 22 23 private final String TAG = "Client"; 24 25 private BookController bookController; 26 27 private boolean connected; 28 29 private List<Book> bookList; 30 private AIDLCallBack callback = new AIDLCallBack.Stub() { //AIDLCallBack AIDL接口的实现 31 @Override 32 public void OnReply() throws RemoteException { 33 Log.e(TAG,"CallBack from Server"); 34 } 35 }; 36 37 private ServiceConnection serviceConnection = new ServiceConnection() { //服务连接类,客户端必须重写一些回调函数 38 @Override 39 public void onServiceConnected(ComponentName name, IBinder service) { //连接-回调函数 40 Log.e(TAG,"回调了onServiceConnected"); 41 bookController = BookController.Stub.asInterface(service); 42 try { 43 bookController.registerCallback(callback); //建立连接时,注册回调函数 44 }catch(RemoteException e){ 45 e.printStackTrace(); 46 } 47 connected = true; 48 } 49 50 @Override 51 public void onServiceDisconnected(ComponentName name) { //断开连接-回调函数 52 connected = false; 53 } 54 }; 55 56 private View.OnClickListener clickListener = new View.OnClickListener() { 57 @Override 58 public void onClick(View v) { 59 switch (v.getId()){ 60 case R.id.btn_getBookList: 61 if(connected){ 62 try{ 63 bookList = bookController.getBookList(); 64 }catch (RemoteException e){ 65 e.printStackTrace(); 66 } 67 log(); 68 } 69 break; 70 case R.id.btn_addBook_inout: 71 if(connected){ 72 Book book = new Book("new Book"); 73 try{ 74 bookController.addBookInOut(book); 75 Log.e(TAG,"向服务器以Inout的方式添加了一本新书"); 76 Log.e(TAG,"新书名:"+book.getName()); 77 }catch(RemoteException e){ 78 e.printStackTrace(); 79 } 80 } 81 break; 82 } 83 } 84 }; 85 86 @Override 87 protected void onCreate(Bundle savedInstanceState) { 88 super.onCreate(savedInstanceState); 89 setContentView(R.layout.activity_main); 90 findViewById(R.id.btn_getBookList).setOnClickListener(clickListener); 91 findViewById(R.id.btn_addBook_inout).setOnClickListener(clickListener); 92 bindService(); 93 } 94 95 @Override 96 protected void onDestroy(){ 97 super.onDestroy(); 98 if(connected){ 99 try { 100 bookController.unregisterCallBack(callback); //申请断开连接前,先去注册回调函数 101 }catch (RemoteException e){ 102 e.printStackTrace(); 103 } 104 unbindService(serviceConnection); //断开连接 105 } 106 } 107 108 private void bindService(){ 109 Intent intent = new Intent(); 110 intent.setPackage("com.example.aidltest_server"); 111 intent.setAction("com.example.aidltest_server.AIDLTEST"); 112 bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE); //对服务端发起连接请求 113 } 114 115 private void log(){ 116 for(Book book:bookList){ 117 Log.e(TAG,book.toString()); 118 } 119 } 120 }
6、一些问题:
如果通过AIDL方式远程调用耗时任务,可能会导致客户端产生ANR;所以要注意客户端如果要调用耗时任务时,可以把调用放在非UI线程中进行;
还有一种情况,Binder可能意外死亡,往往是由于服务端进程意外停止了;这时候我们需要重新连接服务,有两种方法:
1、给Binder设置DeathRecipient监听,当Binder死亡时,我们会收到binderDied回调;->在Binder的线程池中被回调
onServiceConnected函数中,当客户端绑定远程服务时,给binder设置死亡代理,当Binder死亡时,客户端会收到通知,可以在该通知中重连远程服务;
1 private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() { 2 @Override 3 public void binderDied() { 4 Log.w(TAG, "binderDied: "); 5 mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0); 6 mBinderPool = null; 7 connectBinderPoolService(); 8 } 9 }; 10 };
2、在onServiceDisconnected中重连远程服务;->在客户端的UI线程被回调