在Android中,每个应用程序都有自己的进程,当需要在不同的进程之间进行通信,该如何来实现呢?进程间的通信即IPC通信,这个是android最核心的内容,熟悉了ipc通信android就熟悉了一大半。
在java中是不支持跨进程的内存共享,因此要传递对象就必须把对象解析成系统能够理解的数据编码,以便达到跨进程通信的目的。
在这里就采用AIDL(Android Interface Definition Language 接口定义语言 )方式来实现
AIDL是一种接口定义语言,用于约束两个进程通讯规则,提供给编译器生成代码,实现android设备上两个进程间IPC的通信,AIDL的进程之间的通讯信息首先被转换成AIDL协议信息,然后发送给对方,对方接收到AIDL协议信息后又转换成相应的对象。由于进程间通信信息需要双向转换,所以android采用代理类的形式在背后执行双向转换,代理类由android编译器生成,对开发人员来说是透明的,不需要知道如何实现。
实现跨进程通信一般需要四个步骤:
假如A应用需要跨进程调用B应用的一个方法,B应用以service的方式为A应用提供服务
1.在B应用中编写.aidl文件
package com.android.aidl;
interface QueryService {
String queryStudent(int no);
}
当.aidl文件创建完成之后,刷新eclipse会自动在gen目录下生成QueryService.java接口文件
代码如下:
private final class StudentBinder extends QueryService.Stub{
public String queryStudent(int no) throws RemoteException {
Log.i("StudentService", no+"");
return query(no);
}
}
3.在B应用中创建一个Service,在服务的onBind(Intent intent) 方法中返回实现了aidl接口的对象,在这里是StudentBinder对象
代码如下:
package com.android.remoteservice;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.android.aidl.QueryService;
public class StudentService extends Service {
private String[] names = {"成龙", "李连杰", "洪金宝"};
private IBinder binder = new StudentBinder();
private String query(int no){
if(no > 0 && no <4){
return names[no - 1];
}
return null;
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
private final class StudentBinder extends QueryService.Stub{
public String queryStudent(int no) throws RemoteException {
Log.i("StudentService", no+"");
return query(no);
}
}
}
4.把B应用中aidl文件所在package连同aidl文件一起拷贝到客户端A应用,eclipse会自动在A应用的gen目录中为aidl文件同步生成QueryService.java接口文件,接下来就可以在A应用中实现与B应用通信
A应用布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/number"
/>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/number"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button"
android:onClick="query"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/resultView"
/>
</LinearLayout>
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, MainActivity!</string>
<string name="app_name">访问远程服务</string>
<string name="number">学号</string>
<string name="button">查询</string>
</resources>
MainActivity.java
package com.android.service.client;
import com.android.aidl.QueryService;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends Activity {
private EditText numberText;
private TextView resultView;
private StudentConnection conn = new StudentConnection();
private QueryService queryService;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
numberText = (EditText) this.findViewById(R.id.number);
resultView = (TextView) this.findViewById(R.id.resultView);
Intent service = new Intent("com.android.process.aidl.QueryService");
bindService(service, conn, BIND_AUTO_CREATE);
}
private final class StudentConnection implements ServiceConnection{
public void onServiceConnected(ComponentName name, IBinder service) {
queryService = QueryService.Stub.asInterface(service);
}
public void onServiceDisconnected(ComponentName name) {
queryService = null;
}
}
public void query(View v){
String number = numberText.getText().toString();
try {
String name = queryService.queryStudent(Integer.valueOf(number));
resultView.setText(name);
} catch (Exception e) {
e.printStackTrace();
}
}
}