一、引言
AIDL是android內(nèi)部進(jìn)程通信接口的描述語言,是實(shí)現(xiàn)跨進(jìn)程方法調(diào)用的一大利器,其中Binder和Messenger的實(shí)現(xiàn)機(jī)制都是AIDL。
二、使用下面結(jié)合示例說明其使用過程:
本次示例的基本要求是完成一個(gè)圖書館圖書入庫和在庫圖書列表查詢的demo,
1、為了完成這個(gè)功能,我們首先需要一個(gè)實(shí)體類Book,這個(gè)實(shí)體類需要序列化,因?yàn)橹挥行蛄谢院蟮腂ook對象才能在AIDL中使用。
2、接下來我們需要新建Book.aidl和IBookManager.aidl
我們需要在Book.aidl聲明這個(gè)Book類,并在IBookManager中導(dǎo)入Book.aidl并實(shí)現(xiàn)兩個(gè)功能:addBook和getBookList
3.reBuild項(xiàng)目,這樣就會(huì)自動(dòng)生成IbookManager.java這個(gè)AIDL文件。(如果查找不到Book類,請參看我的另外一篇文章,Binder的機(jī)制淺析)
4.接下來的我們就需要在客戶端和服務(wù)端完成對應(yīng)的工作:
下面簡單介紹一下Service和Client中的實(shí)現(xiàn)內(nèi)容。(具體代碼在最后貼出)
Service:服務(wù)端的工作的關(guān)鍵其實(shí)在于實(shí)現(xiàn)Binder,而這個(gè)Binder的獲取就是去實(shí)例化IBookManager.Stub這個(gè)內(nèi)部類,并實(shí)現(xiàn)AIDL接口中聲明的方法 ,最后在onBind中返回這個(gè)Binder實(shí)例即可。
Client:客戶端則首先需要綁定遠(yuǎn)程服務(wù),然后在綁定成功后將服務(wù)端返回的IBinder對象轉(zhuǎn)換為AIDL接口,然后就可以通過這個(gè)接口去調(diào)用服務(wù)端的遠(yuǎn)程方法了。(這里需要注意的是,如果服務(wù)端中實(shí)現(xiàn)的方法為耗時(shí)方法,在客戶端中對它進(jìn)行遠(yuǎn)程調(diào)用的時(shí)候需要在子線程中進(jìn)行,原理在Binder機(jī)制中談到過,因?yàn)榭蛻舳嗽谶M(jìn)行遠(yuǎn)程調(diào)用的時(shí)候,會(huì)掛起自身,等待服務(wù)端的反饋,這個(gè)時(shí)候如果在主線程則會(huì)堵塞主線程)
上面的例子相當(dāng)于是客戶端遠(yuǎn)程調(diào)用服務(wù)端中的方法,下面講的一個(gè)擴(kuò)充相當(dāng)于是服務(wù)端遠(yuǎn)程調(diào)用客戶端中的方法
場景描述:假設(shè)還有一個(gè)需求是用戶希望圖書館在新書入庫的時(shí)候通知他
不難發(fā)現(xiàn)這其實(shí)就是觀察者模式的經(jīng)典引用。這個(gè)時(shí)候我們需要增加一個(gè)AIDL接口,每個(gè)用戶需要實(shí)現(xiàn)這個(gè)接口并向圖書館申請新書的提醒功能,并且可以隨時(shí)取消這個(gè)提醒。而服務(wù)端則會(huì)維持一個(gè)listener的注冊表,當(dāng)新書到庫時(shí),遍歷并通知當(dāng)前已經(jīng)注冊了提醒功能的用戶新書到庫。
這邊我們創(chuàng)建一個(gè)接口IOnNewBookArrivedListener.aidl,并且在原有的接口中新增兩個(gè)方法,注冊和注銷。
Service:在服務(wù)端,我們首先需要實(shí)現(xiàn)注冊和注銷兩個(gè)方法,然后在實(shí)現(xiàn)一個(gè)新的方法用于不斷生成新書,并在新書到來時(shí)遠(yuǎn)程調(diào)用注冊在案的所有l(wèi)istener的onNewBookArrived方法。
Client:首先客戶端需要注冊IOnNewBookArrivedListener到遠(yuǎn)程服務(wù)器,并且在Activity退出時(shí)解除注冊;另外,當(dāng)有新書時(shí),服務(wù)端會(huì)在有新書時(shí)回調(diào)客戶單的IOnNewBookArrivedListener方法,當(dāng)然這個(gè)方法是在客戶端的Binder線程池中進(jìn)行的,因此,為了進(jìn)行UI操作,我們需要使用一個(gè)Handler來將其切換到主線程中執(zhí)行。
具體代碼:
實(shí)體類:
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); //并發(fā)容器BookList private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>(); //并發(fā)容器 Listeners private RemoteCallbackList<IOnNewBookArrivedListener> mListeners = new RemoteCallbackList<>(); //實(shí)例化Binder,實(shí)例化AIDL中的Stub內(nèi)部類, 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); } /** * 注冊監(jiān)聽器,監(jiān)聽圖書進(jìn)庫 * @param listener * @throws RemoteException */ @Override public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException { mListeners.register(listener); } /** * 解除注冊監(jiān)聽器,取消監(jiān)聽圖書進(jìn)庫 * @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")); //啟動(dòng)后臺(tái)線程 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; } //后臺(tái)線程,負(fù)責(zé)不斷產(chǎn)生新書入庫 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