AndroidStudio 和 EclipseADT 创建项目时的 aidl 通信

Eclipse 用的人不多,在使用 aidl 实现进程间通信的时候,studio 和 eclipse 还是有点儿区别的。比如现在我们要实现一个求和功能,client 只负责输入,service 负责计算功能。
client 界面:
求和

1.使用 Eclipse 编写 Service 代码

service 目录结构:
service
Calculate.aidl:

1
2
3
4
5
package com.demo.aidl;

interface Calculate{
double doCalculate(double a,double b);
}

CalculateService:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.demoserver;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

import com.demo.aidl.Calculate;

public class CalculateService extends Service {

@Override
public IBinder onBind(Intent arg0) {
return mBinder;
}

private final Calculate.Stub mBinder = new Calculate.Stub() {

@Override
public double doCalculate(double a, double b) throws RemoteException {
return a + b;
}
};
}

注意:CalculateService 需要在清单文件里注册并设置 action

1
2
3
4
5
6
7
<service
android:name="com.demoserver.CalculateService"
android:exported="true" >
<intent-filter>
<action android:name="com.demoserver.CalculateService" />
</intent-filter>
</service>

2.使用 Eclipse 编写 client:

client1
这里的 Calculate.aidl 都必须和 Service 端一样,界面太简单,不再贴出,MainActivity 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class MainActivity extends Activity {
private EditText numEt1, numEt2;
private Button calculateBtn;
private Calculate mService;
private ServiceConnection conn = new ServiceConnection() {

@Override
public void onServiceDisconnected(ComponentName arg0) {
mService = null;
}

@Override
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
mService = Calculate.Stub.asInterface(arg1);
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
numEt1 = (EditText) findViewById(R.id.numEt1);
numEt2 = (EditText) findViewById(R.id.numEt2);
calculateBtn = (Button) findViewById(R.id.calculateBtn);
calculateBtn.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {
gotoCalculate();
}
});
Intent intent = new Intent("com.demoserver.CalculateService");
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}

private void gotoCalculate() {
double num1 = Double.parseDouble(numEt1.getText().toString());
double num2 = Double.parseDouble(numEt2.getText().toString());
try {
String text = "Sum=" + mService.doCalculate(num1, num2);
Toast.makeText(MainActivity.this, text, Toast.LENGTH_LONG).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}

隐式启动服务,可以完成计算求和功能。

3.使用 Android Studio 编写 client 代码的不同之处:

目录结构:
client2
需要建一个文件夹,名为 aidl,和java文件夹同级,这里面的Calculate.aidl的包名和内容都和 service 端相同。然后手动 rebuild 一下,可以看到自动生成的 java 文件:
java1
启动服务时,5.0 以上的系统会报错:

1
2
3
4
java.lang.RuntimeException: Unable to start activity
ComponentInfo{lpj.com.tests/lpj.com.tests.MainActivity}:
java.lang.IllegalArgumentException: Service Intent must be explicit: Intent {
act=com.demoserver.CalculateService }

因为隐式启动服务需要告诉 Intent 包名:

1
2
3
Intent intent = new Intent("com.demoserver.CalculateService");
intent.setPackage("com.demoserver");
bindService(intent, conn, Context.BIND_AUTO_CREATE);

多加这句intent.setPackage("com.demoserver")就 OK 了。