昨天学习aidl的时候写了个例子,中间遇到一些问题,比如客户端怎么也绑定不了服务端,后面发现是服务端的服务没有起来。这里分享一下,遇到问题的可以参考一下。
代码下载地址:http://download.csdn.net/detail/crazyman2010/9635323
这个例子有两个应用,一个叫ServiceA作为服务端,一个叫ClientB作为客户端。
服务端
1.设计服务端要提供的接口:
List<Book> getBookList(); //返回当前书藉列表
void addBook(Book book); //增加一本书
2.定义接口需要的参数类型
根据接口,定义可以进行IPC的Book类(需要继承Parcelable接口),注意它需要放到ServiceA的src目录下,不然无法编译,内容如下:
package com.heyy.example.servicea;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by mo on 16-9-19.
*/
public class Book implements Parcelable {
public int id;
public String name;
public Book(int id, String name) {
this.id = id;
this.name = name;
}
protected Book(Parcel in) {
id = in.readInt();
name = 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];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
}
}
3.定义接口AIDL和参数AIDL文件
建立接口AIDL文件IBookManager.aidl:
package com.heyy.example.servicea;
import com.heyy.example.servicea.Book;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
}
为参数Book类建立Book.aidl文件:
package com.heyy.example.servicea;
parcelable Book;
4.导出远程服务接口
编译一下,会生成app/build/generated/source/aidl/debug/com/heyy/example/servicea/IBookManager.java文件,这个文件中有Stub类。
新建一个服务BookManagerService:
package com.heyy.example.servicea;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class BookManagerService extends Service {
private CopyOnWriteArrayList<Book> mBookList;
public BookManagerService() {
mBookList = new CopyOnWriteArrayList<>();
mBookList.add(new Book(1, "book1"));
mBookList.add(new Book(2, "book2"));
}
@Override
public IBinder onBind(Intent intent) {
Log.i("aidl","service a bind!");
return mBinder;
}
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);
}
};
}
然后在AndroidManifest.xml中添加ACTION过滤器,以供客户端远程绑定到此服务:
<service
android:name="com.heyy.example.servicea.BookManagerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.heyy.example.servicea.BookManager" />
</intent-filter>
</service>
最后,别忘记启动时要启动此服务,因为在客户端是没法启动服务的:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(this, BookManagerService.class));
}
服务端目录结构图:
客户端
1.复制服务端所有的.aidl文件和参数类到src目录,并保持包名和目录不变。
2.实现ServiceConnection
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IBookManager bookManager = IBookManager.Stub.asInterface(service);
try {
List<Book> books = bookManager.getBookList();
Log.i(TAG, "get books:" + books.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
3.绑定到远程服务
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setAction("com.heyy.example.servicea.BookManager");
Intent explicitIntent = createExplicitFromImplicitIntent(this, intent);
boolean bindResult = bindService(explicitIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
Log.i(TAG, "bind result:" + bindResult);
}
public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
// Retrieve all services that can match the given intent
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo == null || resolveInfo.size() != 1) {
return null;
}
// Get component info and create ComponentName
ResolveInfo serviceInfo = resolveInfo.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent = new Intent(implicitIntent);
// Set the component to be explicit
explicitIntent.setComponent(component);
return explicitIntent;
}
客户端目录结构: