AIDL 全称:android interface defination language 安卓接口定义语言。适用于进程间通信。
首先创建Book对象
package com.example.test.aidl;
import android.os.Parcel;
import android.os.Parcelable;
import java.io.Serializable;
/**
* Description:
*/
public class Book implements Parcelable{
private int bookId;
private String bookName;
public Book(int bookId,String bookName){
this.bookId = bookId;
this.bookName = bookName;
}
protected Book(Parcel in) {
bookId = in.readInt();
bookName = in.readString();
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
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(bookId);
dest.writeString(bookName);
}
}
创建Book.aidl文件
修改Book.aidl内容
package com.example.test.aidl;
parcelable Book;
再创建IBookManager.aidl文件
提供两个方法,addBook和getBookList方法
package com.example.test.aidl;
import com.example.test.aidl.Book;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
}
接下来就服务端,创建BookManagerService继承Service,在onCreate()中初始化添加了4本书。并创建一个Binder对象在onBind()中返回。
package com.example.test.aidl;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Description:
*/
public class BookManagerService extends Service{
private static final String TAG = "BookManagerService";
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
};
@Override
public void onCreate() {
super.onCreate();
mBookList.add(new Book(1,"西游记"));
mBookList.add(new Book(2,"红楼梦"));
mBookList.add(new Book(3,"水浒传"));
mBookList.add(new Book(4,"三国演义"));
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
在AndroidManifest.xml中注册
<service
android:name=".aidl.BookManagerService"
android:process=":BookManagerService">
</service>
创建AidlActivity,和BookManagerService建立连接。
package com.example.test.aidl;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import com.example.test.R;
import java.util.List;
public class AidlActivity extends AppCompatActivity {
private static final String TAG = "AidlActivity";
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IBookManager iBookManager = IBookManager.Stub.asInterface(service);
try {
List<Book> bookList = iBookManager.getBookList();
for (int i = 0; i < bookList.size(); i++) {
Book book = bookList.get(i);
Log.e(TAG, "Book: bookName ————"+book.getBookName() +"||| bookId ————" +book.getBookId());
}
} catch (RemoteException e) {
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aidl);
Intent intent = new Intent(this,BookManagerService.class);
bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(mServiceConnection);
super.onDestroy();
}
}
运行程序,查看控制台数据。
在这里只调用了getBookList()方法,尝试调用一下addBook()方法。修改如下:
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IBookManager iBookManager = IBookManager.Stub.asInterface(service);
try {
//添加一本书籍
iBookManager.addBook(new Book(5,"三打白骨精"));
List<Book> bookList = iBookManager.getBookList();
for (int i = 0; i < bookList.size(); i++) {
Book book = bookList.get(i);
Log.e(TAG, "Book: bookName ————"+book.getBookName() +"||| bookId ————" +book.getBookId());
}
} catch (RemoteException e) {
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
重新运行,发现数据已经添加上去了。
下面我们来模拟一下每当有新的图书添加进来就通知用户。首先需要提供一个AIDL接口,用户可以开启提醒和取消提醒。
首先创建IOnNewBookArrivedListener.aidl文件,并提供onNewBookArrived()方法
// IOnNewBookArrivedListener.aidl
package com.example.test.aidl;
import com.example.test.aidl.Book;
// Declare any non-default types here with import statements
interface IOnNewBookArrivedListener {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void onNewBookArrived(in Book book);
}
然后在原有的IBookManager.aidl中添加两个新方法
package com.example.test.aidl;
import com.example.test.aidl.Book;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
void registerListener(IOnNewBookArrivedListener listener);
void unregisterListener(IOnNewBookArrivedListener listener);
}
BookManagerService中也需要修改下,并在OnCreate()中启动了一个线程,每隔5秒添加一本新书到BookList中。
package com.example.test.aidl;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Description:
*/
public class BookManagerService extends Service{
private static final String TAG = "BookManagerService";
private AtomicBoolean mAtomicBoolean = new AtomicBoolean(false);
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
private CopyOnWriteArrayList<IOnNewBookArrivedListener> mListenerList = new CopyOnWriteArrayList<>();
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
@Override
public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
if (!mListenerList.contains(listener)) {
mListenerList.add(listener);
}
Log.e(TAG, "registerListener: mListenerList大小"+mListenerList.size());
}
@Override
public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
if (mListenerList.contains(listener)) {
mListenerList.remove(listener);
}else{
Log.e(TAG, "找不到该listener -----");
}
Log.e(TAG, "registerListener: mListenerList大小"+mListenerList.size());
}
};
@Override
public void onCreate() {
super.onCreate();
mBookList.add(new Book(1,"西游记"));
mBookList.add(new Book(2,"红楼梦"));
mBookList.add(new Book(3,"水浒传"));
mBookList.add(new Book(4,"三国演义"));
new Thread(new ServiceWorker()).start();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private void onNewBookArrived(Book book) throws RemoteException {
mBookList.add(book);
for (int i = 0; i < mListenerList.size(); i++) {
IOnNewBookArrivedListener iOnNewBookArrivedListener = mListenerList.get(i);
iOnNewBookArrivedListener.onNewBookArrived(book);
}
}
private class ServiceWorker implements Runnable{
@Override
public void run() {
//为真时一直执行
while (!mAtomicBoolean.get()){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int bookId = mBookList.size()+1;
Book book = new Book(bookId,"火影忍者第"+bookId+"话");
try {
onNewBookArrived(book);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
@Override
public void onDestroy() {
mAtomicBoolean.set(true);
super.onDestroy();
}
}
然后AidlActivity中在连接BookManagerService时开启提醒,即注册,销毁的时候取消提醒,即取消注册。
package com.example.test.aidl;
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 com.example.test.R;
import com.example.test.utils.Constants;
import java.util.List;
public class AidlActivity extends AppCompatActivity {
private static final String TAG = "AidlActivity";
private IBookManager mIBookManager;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IBookManager iBookManager = IBookManager.Stub.asInterface(service);
try {
mIBookManager = iBookManager;
iBookManager.addBook(new Book(5,"三打白骨精"));
List<Book> bookList = iBookManager.getBookList();
for (int i = 0; i < bookList.size(); i++) {
Book book = bookList.get(i);
Log.e(TAG, "Book: bookName ————"+book.getBookName() +"||| bookId ————" +book.getBookId());
}
//注册
iBookManager.registerListener(mIOnNewBookArrivedListener);
} catch (RemoteException e) {
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case Constants.BOOKARRIVED:
Book book = (Book) msg.obj;
Log.e(TAG, "Book: bookName ————"+book.getBookName() +"||| bookId ————" +book.getBookId());
break;
default:
super.handleMessage(msg);
break;
}
}
};
private IOnNewBookArrivedListener mIOnNewBookArrivedListener = new IOnNewBookArrivedListener.Stub() {
@Override
public void onNewBookArrived(Book book) throws RemoteException {
mHandler.obtainMessage(Constants.BOOKARRIVED,book).sendToTarget();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aidl);
Intent intent = new Intent(this,BookManagerService.class);
bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
if (mIBookManager != null && mIBookManager.asBinder().isBinderAlive()) {
try {
//取消注册
mIBookManager.unregisterListener(mIOnNewBookArrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
unbindService(mServiceConnection);
super.onDestroy();
}
}
然后重新运行程序。可以看出来每隔5秒就会收到新书的消息。
那么问题来了,销毁AidlActivity 时取消提醒时并没有移除该listener
失败原因是因为Binder会把传递过来的对象重新转化并生成一个新的对象,所以会出现取消提醒失败的现象。那么解决办法是什么呢,那就需要用到了RemoteCallbackList。
RomoteCallbackList 是系统专门提供用于删除跨进程listener的接口
修改BookManagerService
private RemoteCallbackList<IOnNewBookArrivedListener> mListenerList = new RemoteCallbackList<>();
@Override
public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
mListenerList.register(listener);
int size = mListenerList.beginBroadcast();
Log.e(TAG, "registerListener: mListenerList大小"+size);
mListenerList.finishBroadcast();
}
@Override
public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
mListenerList.unregister(listener);
int size = mListenerList.beginBroadcast();
Log.e(TAG, "unregisterListener: mListenerList大小:"+size);
mListenerList.finishBroadcast();
}
private void onNewBookArrived(Book book) throws RemoteException {
mBookList.add(book);
int size = mListenerList.beginBroadcast();
for (int i = 0; i < size; i++) {
IOnNewBookArrivedListener listener = mListenerList.getBroadcastItem(i);
listener.onNewBookArrived(book);
}
mListenerList.finishBroadcast();
}
然后重新运行程序,可以看到可以开启提醒和取消提醒了。
RomoteCallbackList 的beginBroadcast()和finishBroadcast()必须配对使用。
权限验证
在AndroidManifest.xml中添加
<permission android:name="Permission.BookManagerService"
android:protectionLevel="normal" />
<uses-permission android:name="Permission.BookManagerService"/>
BookManagerService中的onBInd()进行验证
@Nullable
@Override
public IBinder onBind(Intent intent) {
int i = checkCallingOrSelfPermission("Permission.BookManagerService");
Log.e(TAG, "onBind: i "+i);
if (i == PackageManager.PERMISSION_DENIED) {
return null;
}
return mBinder;
}