Android中有事遇到在不同进程间进行通信,此时我们有两种实现方式。其一使用Messenger,其二使用AIDL。
Messenger在http://blog.csdn.net/chenfeng0104/article/details/7010244写的比较详细,需要了解的同学可以进去看看。我今天就对这几天研究的AIDL做个记录。
AIDL(Android Interface Definition Language)是一种接口定义语言,编译器通过*.aidl文件的描述信息生成符合通信协议的Java代码,我们无需自己去写这段繁杂的代码,只需要在需要的时候调用即可,通过这种方式我们就可以完成进程间的通信工作。
首先编写服务端app,创建一个demo,先看下文件结构:
要创建一个aidl文件AIDLService.aidl和入口Activity类MainActivity,app的Application类和app的Service类。(https://img-blog.csdn.net/20151030142702963)。
先看下aidl文件:
package com.aidl.binder.message;
interface AIDLService{
String getMessage(String str);
String infoMessage(String str);
}
接口中有两个未实现的方法。
AIDLServerService类实现:
package com.aidl.server;
import android.app.Service;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.aidl.binder.message.AIDLService;
public class AIDLServerService extends Service {
AIDLService mService;
private String TAG = "AIDLServerService";
@Override
public void onCreate() {
super.onCreate();
mService = new AIDLService.Stub() {
@Override
public String infoMessage(String str) throws RemoteException {
return "you call method infoMessage(String str) and parameter " + str ;
}
@Override
public String getMessage(String str) throws RemoteException {
return "you call method getMessage(String str) and parameter " + str ;
}
};
}
@Override
public IBinder onBind(Intent intent) {
return (IBinder) mService;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestory AIDLServerService");
mService = null;
}
@Override
public void unbindService(ServiceConnection conn) {
super.unbindService(conn);
Log.e(TAG, "unbindService");
}
}
在AIDLServerService里我们实现了AIDLService的两个方法。并在onBind(Intent intent)方法中return AIDLService的对象。
Application类实现很简单,就是用于启动AIDLServerService.
public class AssistProjectApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
startService(new Intent(this, AIDLServerService.class));
}
@Override
public void onTerminate() {
super.onTerminate();
}
}
入口activity中不需要做处理。
AndroidManifest文件配置:
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.aidl.server.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.aidl.server.reside.menu.MenuActivity"/>
<service android:name="com.aidl.server.AIDLServerService">
<intent-filter>
<action android:name="com.aidl.server.Action.AIDLServerService"/>
</intent-filter>
</service>
</application>
现在看下客户端app的实现:
客户端创建一个和服务端包名及aidl文件一致的.aidl文件,方便考虑,可以直接copy到客户端。。
客户端调用aidl的实现Activity:
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.aidl.binder.message.AIDLService;
import com.syp.assistprogect.R;
public class AIDLServiceActivity extends Activity implements OnClickListener{
private String TAG = "AIDLServiceActivity";
private TextView mTxtShow;
private Button mBtnGet;
private Button mBtnInfo;
private Button mBtnBinder;
private AIDLService mService = null;
private boolean isBinder = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aidl_ipc_layout);
mTxtShow = (TextView) findViewById(R.id.txt_ipc_aidl_show);
mBtnGet = (Button) findViewById(R.id.btn_ipc_get);
mBtnInfo = (Button) findViewById(R.id.btn_ipc_info);
mBtnBinder = (Button) findViewById(R.id.btn_ipc_bundle_aidl);
mBtnGet.setOnClickListener(this);
mBtnInfo.setOnClickListener(this);
mBtnBinder.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.btn_ipc_get:
if(isBinder && mService != null){
try {
String data = mService.getMessage("aidl test");
Log.i(TAG, "call getMessage() and return :" + data);
mTxtShow.setText(mService.getMessage("aidl test"));
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
}
break;
case R.id.btn_ipc_info:
if(isBinder && mService != null){
try {
String data = mService.getMessage("aidl test");
Log.i(TAG, "call infoMessage() and return :" + data);
mTxtShow.setText(mService.infoMessage("aidl test"));
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
}
break;
case R.id.btn_ipc_bundle_aidl:
binderAIDLService();
break;
default:
break;
}
}
private String serviceAction = "com.aidl.server.Action.AIDLServerService";//服务端service的action
private void binderAIDLService(){
Intent intent = new Intent(serviceAction);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
Log.e(TAG, "binderAIDLService ->intent = " + intent);
}
ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
isBinder = false;
Toast.makeText(AIDLServiceActivity.this, "service has disconnected", Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = AIDLService.Stub.asInterface(service);
isBinder = true;
Toast.makeText(AIDLServiceActivity.this, "service has Connected", Toast.LENGTH_SHORT).show();
}
};
protected void onDestroy() {
super.onDestroy();
if(mService != null){
unbindService(mConnection);
mService = null;
}
};
}
注意在退出activity时,要断开binderservice的连接,请看onDestroy();
最后我在使用时发现一个奇怪的事情,如果我把客户端aidl中的两个方法换下顺序,`package com.aidl.binder.message;
interface AIDLService{
String infoMessage(String str);
String getMessage(String str);
}`
发现在调用getMessage(String str)方法时,返回的结果是infoMessage(String str)的实现。
找了很久问题所在,发现在我们创建aidl文件后,在服务端app下gen生成的方法如下。
在客户端app下的gen目录生成两方法如下
最终调用方法时是由TRANSACTION_getMessage的值来决定的,和方法名称没关系。所以在使用aidl实现多个方法时,注意保持方法顺序在CS两点的一直。