在开始本章之前,先向大家介绍COM的一个概念---------Proxy/Stub结构(代理/存根结构)
打个比方,你到自动取款机上去取款;你就是客户,取款机就是你的代理;你不会在乎钱具体放在那里,你只想看到足够或更多的钱从出口出来(这就是com的透明性)。你同银行之间的操作完全是取款机代理实现。你的取款请求通过取款机,传到另一头,银行的服务器,他也没有必要知道你在哪儿取钱,他所关心的是你的身份,和你取款多少。当他确认你的权限,就进行相应的操作,返回操作结果给取款机,取款机根据服务器返回结果,从保险柜里取出相应数量的钱给你。你取出卡后,操作完成。取款机不是直接同服务器连接的,他们之间还有一个“存根”,取款机与存根通信,服务器与存根通信。从某种意义上说存根就是服务器的代理。
AIDLFramework层的架构,如下图:
Android就是在传统的C/S架构中加入了一层,实现IPC。我们下面来详细介绍一下android的aidl实现原理
AIDL(Android接口定义语言)是类似于其他你遇到过的IDL。它允许您定义的编程接口,客户端和服务达成一致,以互相交流使用进程间通信(IPC)。在Android上,一个进程无法正常访问另一个进程的内存,而AIDL可以为你实现。AIDL的使用呢和我之前写的Messenger的使用有着很大的区别,我们先要搭建一个aidl服务端,搭建服务端有以下三个步骤(1)创建aidl文件,这个文件将定义方法签名的编程接口。当你构建aidl文件,Android SDK工具将自动生成一个基于内部的接口。,并将aidl文件其保存在项目的创/目录。(2)实现接口.Android SDK工具自动生成的基于aidl接口的Java编程语言接口。这个接口有一个名为stub的内在抽象类,扩展了ibinder从AIDL接口和实现方法。你必须扩展Stub类和并且实现方法。(3)公开接口给客户端。实现一个Service并覆盖onBind()返回你的stub类的实现。
服务器端框架
DataService.aidl源代码如下:
package com.example.service; interface DataService{ int getData(String name); }
MyService的源代码:
package com.example.f25_aidl01; import com.example.service.DataService; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; public class MyService extends Service { @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); } private final DataService.Stub mBinder=new DataService.Stub(){ @Override public int getData(String name) throws RemoteException { // TODO Auto-generated method stub if(name.equals("1")){ return 1; } return 0; } }; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return mBinder; } }
在启动Client之前先要启动服务器端的Service,并在清单文件如下写到
<service android:name="com.example.f25_aidl01.MyService"> <intent-filter> <action android:name="com.example.service.DataService"/> </intent-filter> </service>
Client要注意必须和服务端一样声明一个一摸一样的aidl文件。
MainAcitivity的源代码
package com.example.f25_aidl_client; import com.example.service.DataService; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.util.Log; import android.view.Menu; import android.view.View; import android.widget.Button; import android.widget.Toast; public class MainActivity extends Activity { private Button button, button2; private DataService dataService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) this.findViewById(R.id.button1); button2 = (Button) this.findViewById(R.id.button2); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Intent intent = new Intent(DataService.class.getName()); bindService(intent, connection, Context.BIND_AUTO_CREATE); } }); button2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub try { int a = dataService.getData("1"); Toast.makeText(MainActivity.this, "---->"+a, Toast.LENGTH_LONG).show(); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); } ServiceConnection connection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub Log.i("TAG", "-------->unbind"); } @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub dataService = DataService.Stub.asInterface(service); } }; @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }