1 Service的生命周期
2 aidl使用步骤
- 在工程中创建aidl目录,该目录与java目录同级
这里是在一个工程中模拟两个进程间通信,如果是两个工程的操作,则把要调用的aidl目录拷贝到自己的工程中,注意aidl目录下的包名要与自己工程的包名相同):
右键->New->Folder->AIDL Folder
- 在aidl目录中创建了与要调用的工程相同的包名后,创建AIDL接口
右键->New->AIDL->AIDL File
如果AIDL接口中要使用自定义对象,则先在adil目录中创建自定义对象(注意,该对象必须实现Parcelable接口),并创建与该对象相同名的AIDL文件
- 自定义对象
// Book.java
package com.vincent;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable {
public int bookId;
public String bookName;
private Book(Parcel in) {
bookId = in.readInt();
bookName = in.readString();
}
public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
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];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(bookId);
parcel.writeString(bookName);
}
}
- 自定义对象的AIDL文件
// Book.aidl
package com.vincent;
parcelable Book;
- AIDL接口
// IBookManager.aidl
package com.vincent;
import com.vincent.Book; //注意,在AIDL接口的方法中要使用自定义对象或相关的aidl文件对象,都需要显式的导入对象
interface IBookManager {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
List<Book> getBookList();
void addBook(in Book book);
}
- 在app工程目录下的
build.gradle
的android{}
下添加以下代码
不添加会导致自定义对象无法找到报错,如果aidl目录是在其他工程下,该工程和自己的工程的 build.gradle
都要添加
sourceSets{
main {
java.srcDirs = ['src/main/java', 'src/main/aidl']
resources.srcDirs = ['src/main.java', 'src/main/adil']
}
}
以上执行完成后,Build->Make Project重新build工程
- 在
java/packageName
目录下创建要调用AIDL接口的服务
BookManagerService.java
//该服务的操作是在onCreate()的时候添加两本书,在getBookList()返回mBookList,addBook()添加书本
public class BookManagerService extends Service {
private static final String TAG = "BMS";
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
private Binder mBinder = new IBookManager.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@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, "Android"));
mBookList.add(new Book(2, "IOS"));
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
- 绑定服务调用AIDL接口
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
IBookManager bookManager = IBookManager.Stub.asInterface(iBinder);
try {
List<Book> list = bookManager.getBookList();
Log.i(TAG, "query book list : " + getBookName(list));
Book newBook = new Book(3, "SQL");
bookManager.addBook(newBook);
List<Book> newList = bookManager.getBookList();
Log.i(TAG, "query book list: " + getBookName(newList));
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
private String getBookName(List<Book> bookList) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bookList.size(); i++) {
Book book = bookList.get(i);
if (i == bookList.size() - 1) {
sb.append(book.bookName);
break;
}
sb.append(book.bookName).append(",");
}
return sb.toString();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, BookManagerService.class);
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
}
如果在AIDL中有使用跨进程的listener,需要使用 RemoteCallbackList<T>
这个集合去注册和解注册listener
-
为了程序健壮性,一般需要设置死亡代理
- 声明DeathRecipient对象,在binder死亡的时候会回调
binderDied()
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { if (mRemoteBookManager == null) return; mRemoteBookManager.asBinder().unlinkToDeath(mDeathRecipient, 0); mRemoteBookManager = null; //重新绑定远程服务 Intent intent = new Intent(MainActivity.this, BookManagerService.class); bindService(intent, mConnection, BIND_AUTO_CREATE); } };
- 在
ServiceConnnection
的onServiceConnected()
中设置死亡代理
private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { IBookManager bookManager = IBookManager.Stub.asInterface(iBinder); try { iBinder.linkToDeath(mDeathRecipient, 0); //设置死亡代理 mRemoteBookManager = bookManager; mRemoteBookManager.registerListener(mOnNewBookArrivedListener); new Thread(new Runnable() { @Override public void run() { if (mRemoteBookManager != null) { try { List<Book> list = mRemoteBookManager.getBookList(); Log.i(TAG, "query book list: " + getBookName(list)); } catch (RemoteException e) { e.printStackTrace(); } } } }).start(); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName componentName) { mRemoteBookManager = null; Log.e(TAG, "binder died."); } };
- 声明DeathRecipient对象,在binder死亡的时候会回调