一、引言
AIDL是android内部进程通信接口的描述语言,是实现跨进程方法调用的一大利器,其中Binder和Messenger的实现机制都是AIDL。
二、使用下面结合示例说明其使用过程:
本次示例的基本要求是完成一个图书馆图书入库和在库图书列表查询的demo,
1、为了完成这个功能,我们首先需要一个实体类Book,这个实体类需要序列化,因为只有序列化以后的Book对象才能在AIDL中使用。
2、接下来我们需要新建Book.aidl和IBookManager.aidl
我们需要在Book.aidl声明这个Book类,并在IBookManager中导入Book.aidl并实现两个功能:addBook和getBookList
3.reBuild项目,这样就会自动生成IbookManager.java这个AIDL文件。(如果查找不到Book类,请参看我的另外一篇文章,Binder的机制浅析)
4.接下来的我们就需要在客户端和服务端完成对应的工作:
下面简单介绍一下Service和Client中的实现内容。(具体代码在最后贴出)
Service:服务端的工作的关键其实在于实现Binder,而这个Binder的获取就是去实例化IBookManager.Stub这个内部类,并实现AIDL接口中声明的方法 ,最后在onBind中返回这个Binder实例即可。
Client:客户端则首先需要绑定远程服务,然后在绑定成功后将服务端返回的IBinder对象转换为AIDL接口,然后就可以通过这个接口去调用服务端的远程方法了。(这里需要注意的是,如果服务端中实现的方法为耗时方法,在客户端中对它进行远程调用的时候需要在子线程中进行,原理在Binder机制中谈到过,因为客户端在进行远程调用的时候,会挂起自身,等待服务端的反馈,这个时候如果在主线程则会堵塞主线程)
上面的例子相当于是客户端远程调用服务端中的方法,下面讲的一个扩充相当于是服务端远程调用客户端中的方法
场景描述:假设还有一个需求是用户希望图书馆在新书入库的时候通知他
不难发现这其实就是观察者模式的经典引用。这个时候我们需要增加一个AIDL接口,每个用户需要实现这个接口并向图书馆申请新书的提醒功能,并且可以随时取消这个提醒。而服务端则会维持一个listener的注册表,当新书到库时,遍历并通知当前已经注册了提醒功能的用户新书到库。
这边我们创建一个接口IOnNewBookArrivedListener.aidl,并且在原有的接口中新增两个方法,注册和注销。
Service:在服务端,我们首先需要实现注册和注销两个方法,然后在实现一个新的方法用于不断生成新书,并在新书到来时远程调用注册在案的所有listener的onNewBookArrived方法。
Client:首先客户端需要注册IOnNewBookArrivedListener到远程服务器,并且在Activity退出时解除注册;另外,当有新书时,服务端会在有新书时回调客户单的IOnNewBookArrivedListener方法,当然这个方法是在客户端的Binder线程池中进行的,因此,为了进行UI操作,我们需要使用一个Handler来将其切换到主线程中执行。
具体代码:
实体类:
package com.pignet.library.aidl;import android.os.Parcel;import android.os.Parcelable;/** * Created by DB on 2017/7/1. */public class Book implements Parcelable{ public int bookId; public String bookName; public Book(int bookId, String bookName) { this.bookId = bookId; this.bookName = bookName; } public int getBookId() { return bookId; } public void setBookId(int bookId) { this.bookId = bookId; } public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(this.bookId); dest.writeString(this.bookName); } public Book() { } protected Book(Parcel in) { this.bookId = in.readInt(); this.bookName = in.readString(); } public static final Creator<Book> CREATOR = new Creator<Book>() { @Override public Book createFromParcel(Parcel source) { return new Book(source); } @Override public Book[] newArray(int size) { return new Book[size]; } }; }
AIDL:
// Book.aidlpackage com.pignet.library.aidl;// Declare any non-default types here with import statementsparcelable Book;
// IBookManager.aidlpackage com.pignet.library.aidl;// Declare any non-default types here with import statementsimport com.pignet.library.aidl.Book;import com.pignet.library.aidl.IOnNewBookArrivedListener;interface IBookManager{ List<Book> getBookList(); void addBook(in Book book); void registerListener(IOnNewBookArrivedListener listener); void unregisterListener(IOnNewBookArrivedListener listener);
// IOnNewBookArrivedListener.aidlpackage com.pignet.library.aidl;import com.pignet.library.aidl.Book;interface IOnNewBookArrivedListener { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void onNewBookArrived(in Book newBook); }
Service端:
package com.pignet.library;import android.app.Service;import android.content.Intent;import android.content.pm.PackageManager;import android.os.Binder;import android.os.IBinder;import android.os.RemoteCallbackList;import android.os.RemoteException;import android.os.SystemClock;import android.support.annotation.Nullable;import android.util.Log;import com.pignet.library.aidl.Book;import com.pignet.library.aidl.IBookManager;import com.pignet.library.aidl.IOnNewBookArrivedListener;import java.util.List;import java.util.concurrent.CopyOnWriteArrayList;import java.util.concurrent.atomic.AtomicBoolean;/** * Created by DB on 2017/7/2. */public class BookManagerService extends Service { private static final String TAG ="BookManagerService"; //原子类,Service是否销毁 private AtomicBoolean mIsServiceDestroyed = new AtomicBoolean(false); //并发容器BookList private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>(); //并发容器 Listeners private RemoteCallbackList<IOnNewBookArrivedListener> mListeners = new RemoteCallbackList<>(); //实例化Binder,实例化AIDL中的Stub内部类, private Binder mBinder = new IBookManager.Stub(){ @Override public List<Book> getBookList() throws RemoteException { SystemClock.sleep(5000); return mBookList; } @Override public void addBook(Book book) throws RemoteException { mBookList.add(book); } /** * 注册监听器,监听图书进库 * @param listener * @throws RemoteException */ @Override public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException { mListeners.register(listener); } /** * 解除注册监听器,取消监听图书进库 * @param listener * @throws RemoteException */ @Override public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException { mListeners.unregister(listener); } }; //初始化图书馆中的图书 @Override public void onCreate() { super.onCreate(); mBookList.add(new Book(1,"Android")); mBookList.add(new Book(2,"Java")); //启动后台线程 new Thread(new ServiceWorker()).start(); } @Nullable @Override public IBinder onBind(Intent intent) { int check = checkCallingOrSelfPermission("com.pignet.library.permission.ACCESS_BOOK_SERVICE"); if(check == PackageManager.PERMISSION_DENIED){ Log.d(TAG, "failed "); return null; } return mBinder; } //后台线程,负责不断产生新书入库 private class ServiceWorker implements Runnable{ @Override public void run() { while(!mIsServiceDestroyed.get()){ try{ Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } int bookId = mBookList.size()+1; Book newBook = new Book(bookId,"new Book#"+bookId); Log.d(TAG, "run: "+bookId); try { onNewBookArrived(newBook); } catch (RemoteException e) { e.printStackTrace(); } } } private void onNewBookArrived(Book newBook) throws RemoteException { mBookList.add(newBook); final int N= mListeners.beginBroadcast(); for(int i=0;i<N;i++){ IOnNewBookArrivedListener listener = mListeners.getBroadcastItem(i); if(listener!=null){ try{ listener.onNewBookArrived(newBook); }catch (RemoteException e){ e.printStackTrace(); } } } mListeners.finishBroadcast(); } } }
client:
package com.pignet.library;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.RemoteException;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;import com.pignet.library.aidl.Book;import com.pignet.library.aidl.IBookManager;import com.pignet.library.aidl.IOnNewBookArrivedListener;import org.w3c.dom.Text;import java.util.List;public class BookManagerActivity extends AppCompatActivity { Button btnGetBookList; Button btnAddBook; TextView tvBookList; EditText etBook; IBookManager bookManager; private static StringBuilder stringBuilder; private static final String TAG="BookManagerActivity"; private static final int MESSAGE_NEW_BOOK_ARRIVED=1; private IBookManager mRemoteBookManager; //建立连接 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnGetBookList = (Button) findViewById(R.id.btn_getBookList); btnAddBook = (Button) findViewById(R.id.btn_addBook); tvBookList = (TextView) findViewById(R.id.tv_bookList); etBook = (EditText) findViewById(R.id.et_addBook); //绑定Service Intent intent =new Intent(BookManagerActivity.this,BookManagerService.class); bindService(intent,mConnection, Context.BIND_AUTO_CREATE); //增加图书 btnAddBook.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(etBook.getText().toString().length()>1){ Log.d(TAG, "add Book"); Book book = null; try { book = new
http://www.cnblogs.com/hustzhb/p/7119762.html