Android IPC通信之AIDL理解
本文就我自己在使用aidl过程中的一些心得与大家分享:
定义 服务端 A 客户端 B;
服务端A操作
- 定义aidl文件
- 定义aidl的方法,可传的参数类型:基本数据类型、ArrayList、String,List,Map,CharSequence等类其他AIDL接口类型、所有Parcelable的类。
- 构建Service类,在onBind方法中需要返回一个IBind的实例,aidl.Stub()方法恰好返回IBind类型,因此在此处返回aidl.Stub(){实现方法};此处实现aidl中定义的方法;
- 注册服务。
客户端B操作
- 定义aidl文件,与服务端的aidl文件完全相同,可直接复制过来,且包名也必须相同(一定注意,个人理解是Android底层在aidl通信时会直接调用服务端的aidl文件进行使用,客户端的aidl文件名称必须指向服务端,不然调用不到,无法通信,而内容一致是方便客户端对方法的调用。(个人理解,如有错误,请指出))。
- 绑定服务,隐式绑定服务端的Service(Android5.0后必须用显式方式,不然会报错,但此处需用隐式,解决方法如下:
Intent intent = new Intent();
intent.setAction("com.a592n.dizner.thrtest.TestgService");
Intent eintent = new Intent(getExplicitIntent(this,intent));
b = bindService(eintent, connection, BIND_AUTO_CREATE);
public static Intent getExplicitIntent(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;
}
);
- 此处必须使用bindService()方法来启动服务(记得调用unBindService()),在ServiceConnection的实现类中得到IBind实例,通过IBind获取aidl实例,aidl.Stub.asInterface(iBinder)即可得到。
- 通过aidl实例对服务端进行操作。
举例如下
- 服务端
aidl文件:
// ITestAidlInterface.aidl
package com.a592n.dizner.thrtest;
// Declare any non-default types here with import statements
interface ITestAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
String basicTypes(String aString);
}
Service:
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
// throw new UnsupportedOperationException("Not yet implemented");
return new ITestAidlInterface.Stub(){
@Override
public String basicTypes(String aString) throws RemoteException {
Log.d("远程会话消息:",aString);
return aString;
}
};
}
- 客户端
aidl文件:
// ITestAidlInterface.aidl
package com.a592n.dizner.thrtest;
// Declare any non-default types here with import statements
interface ITestAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
String basicTypes(String aString);
}
MainActivity 内容:
public class MainActivity extends AppCompatActivity {
private ITestAidlInterface service;
private int i = 0;
private Button bt_txt;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
service = ITestAidlInterface.Stub.asInterface(iBinder);
try {
String s = service.basicTypes("远程服务连接成功");
Toast.makeText(MainActivity.this, s, Toast.LENGTH_LONG).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Toast.makeText(MainActivity.this, "远程服务连接失败", Toast.LENGTH_LONG).show();
}
};
private boolean b;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setAction("com.a592n.dizner.thrtest.TestgService");
Intent eintent = new Intent(getExplicitIntent(this,intent));
b = bindService(eintent, connection, BIND_AUTO_CREATE);
bt_txt = (Button) findViewById(R.id.bt_txt);
}
public void onClick(View view) {
try {
if (b)
bt_txt.setText(service.basicTypes(String.valueOf(i++)));
else
Toast.makeText(MainActivity.this, "服务未连接", Toast.LENGTH_LONG).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(connection);
}
public static Intent getExplicitIntent(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;
}
}