android开发系列之aidl
aidl在android开发中的主要作用就是跨进程通讯来着,说到进程相比很多人都是非常熟悉了,但是为什么会有跨进程通讯这个概念呢?原来在android系统中,有这么一套安全机制,为了各个Apk数据的独立性、安全性,它们彼此之间是不能直接进行数据的访问的。所以为了实现多个APK之间的数据、方法、代码复用,我们通常采用的做法就是定义好AIDL接口,这样就能够既保护现有代码的逻辑性、同时又能够兼顾好封装性,各个团队之间只需要沟通好AIDL接口定义就可以了。
下面让我们直接进入主题吧,在进行AIDL定义的时候,通常会将公用的代码逻辑单独封装到一个独立的APK中,这个APK我们不妨成为服务器Server。当定义好Server断逻辑之后,就可以供其他第三方代码调用了,这个第三方Apk我们不妨成为Client。但是Server和Client方,必须同时保证AIDL文件名称相同,同时又在相同的包名下面。只有同时满足这两点的话,才能利用AIDL进行通讯。
假如有一套公用的计算方法,在多个第三方APK中都需要调用。所以定义两个android project,一个服务端程序AidlServer,一个客户端测试程序TestClient。其中服务端、客户端的AIDL接口文件都位于包“com.example.aidl下面”,定义好ICal.aidl文件,代码如下:
package com.example.aidl; interface ICal{ double doCal(double x,double y); }
在定义书写aidl文件代码的时候,语法规则跟java一致,切记不要忘记引入package或者少写了分号。当定义好aidl文件之后,并且没有错误的情况下,按住ctrl+s键保存编译,会发现项目的gen文件夹下面会自动生成一个同名的java文件。如果到这一步正确的生成了java文件的话,那么说明服务端,客户端的AIDL接口部分已经定义完成,那么接下来怎么将服务端的接口暴露给客户端调用呢?答案是通过service,我们先来看一下service端的CalService代码:
package com.example.service; import com.example.aidl.ICal; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; public class CalService extends Service { private static final String TAG = CalService.class.getName(); @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public void onCreate() { Log.d(TAG,"onCreate action"); super.onCreate(); } @Override public void onStart(Intent intent, int startId) { Log.d(TAG, "onStart action"); super.onStart(intent, startId); } @Override public void onDestroy() { Log.d(TAG, "onDestroy"); super.onDestroy(); } @Override public boolean onUnbind(Intent intent) { Log.d(TAG, "onUnbind"); return super.onUnbind(intent); } private final ICal.Stub mBinder=new ICal.Stub() { @Override public double doCal(double x, double y) throws RemoteException { CalUtils calUtils=new CalUtils(); double result=calUtils.add(x, y); return result; } }; }
通过CalService可以很好的暴露CalUtils公用类里面的计算方法,CalUtils代码如下:
package com.example.service; public class CalUtils{ public double add(double x,double y){ return x+y; } }
最后还需要在AndroidManifest.xml文件里面注册CalService,代码如下:
<service android:name="com.example.service.CalService"> <intent-filter> <action android:name="com.example.service.CalService"/> </intent-filter> </service>
到这里,服务器端的代码逻辑就完了,下面开始Client的测试代码编写。首先定义好一个计算xml页面,里面放置两个EditText、一个TextView、一个Button、一个TextView,这块的xml代码就不放出来了,稍后demo里面有。主要来看看后台的Activity代码,如下:
package com.example.mytestpro; import com.example.aidl.ICal; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.graphics.Color; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class CalActivity extends Activity implements OnClickListener { private static final String TAG=CalActivity.class.getName(); private EditText etX,etY; private Button btnCal; private TextView tvInfo; private ICal mService; private ServiceConnection mServiceConnection=new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "do Disconnected action"); mService=null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "do Connected action"); mService=ICal.Stub.asInterface(service); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_calctivity); initView(); setClick(); startBindServiceAction(); } private void startBindServiceAction(){ Bundle args=new Bundle(); Intent intent=new Intent("com.example.service.CalService"); intent.setPackage("com.example.aidlserver"); intent.putExtras(args); bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); } private void initView(){ etX=(EditText)findViewById(R.id.etX); etY=(EditText)findViewById(R.id.etY); btnCal=(Button)findViewById(R.id.btnCal); tvInfo=(TextView)findViewById(R.id.tvInfo); } private void setClick(){ btnCal.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btnCal: excuteCalAction(); break; default: break; } } private void excuteCalAction(){ try { double x=Double.parseDouble(etX.getText().toString()); double y=Double.parseDouble(etY.getText().toString()); String result="result:"+mService.doCal(x, y); tvInfo.setText(result); tvInfo.setTextColor(Color.RED); } catch (Exception e) { Log.d(TAG, e.getMessage()); } } }