前面的文章,介绍了aidl的几个必要组成部分,以及其关系。这里由一个例子来更好的说明,并且,可以引向更深的问题。
aidl在android应用层里面常用于单独进程的service与activity通讯。如果在同一个进程中的service与activity,当然没必要这样做。这两种使用service的方式,在形式上当然也是有区别的。
现在我们要在一个单独的进程中,实现add方法,并且把结果返回给client。我们知道Binder机制可以实现进程之间通讯,所以Client肯定要能获取到Binder,但是如何获取呢?
public class MainActivity extends AppCompatActivity {
private ITest mITest;
ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//在这里拿到ITest
try {
mITest = ITest.Stub.asInterface(service);
//调用ITest中的方法,实际上是调用了Proxy的方法
int sum = mITest.add(1, 2);
Log.d("test", "sum = " + sum);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, RemoteService.class);
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
}
Proxy是代理的意思,当然是给client用的,但是,Proxy是Stub的私有类,不能直接在client中获取并调用其方法,所以只能通过Stub提供的asInterface方法暴露出来。我们再来看看这个方法
public static com.example.aidl.ITest asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.aidl.ITest))) {
return ((com.example.aidl.ITest)iin);
}
//这里很明显了
return new com.example.aidl.ITest.Stub.Proxy(obj);
}
前几篇文章分析可知,Stub是用在service中的,所以这段代码是好理解的。
public class RemoteService extends Service {
@Override
public IBinder onBind(Intent intent) {
return new TestBinder();
}
//service要实现ITest.aidl中定义的函数,它是真正干活的
class TestBinder extends ITest.Stub{
@Override
public int add(int a, int b) throws RemoteException {
return a+b;
}
}
}
mainifest中的配置 ,让service真正运行在独立的进程当中
<service android:name=".RemoteService"
android:process="com.chopin.test"></service>
更多的思考
这个例子,client是在java层定义,service也是在java层定义,似乎与底层无关。进程之间的通讯,不可能离开系统层的,因为无论是何种机制,都是基于系统层的调用。只不过android的封装,让这些变得简单,隐藏了底层细节。