安卓中AIDL的使用方法快速入门
1.AIDL是什么?
AIDL全称是Android Interface Definition Language,即安卓接口定义语言。
2.AIDL是用来做什么的?(为什么要有AIDL)
AIDL是用来进行进程间通信(IPC全称interprocess communication )的。
3.如何使用AIDL?
对于AIDL的使用,
服务端需要完成的任务是:
①.写一个xxxx.aidl文件
②.写一个Service并在AndroidManifest.xml中声明它。(注意:这个service里面有一个引用了实现xxxx.Stub抽象类的IBinder对象,这个对象将在service的onBind方法里面返回给调用者)
客户端的任务:
①.使用和服务端相同的那个aidl文件
②.在实现了ServiceConnection接口的onServiceConnected(ComponentName name, IBinder service)方法中调用myvar = testidl.Stub.asInterface(service)保存得到的对象,其中myvar是xxxx的类型
这么说还是不够清楚,下面直接上代码。
首先是服务端的
//testidl.idl文件的内容 package com.example.xxnote; interface testidl { void TestFunction(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); }
//myaidlservice.java文件的内容 package com.example.xxnote; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; public class myaidlservice extends Service { private final IBinder myStub = new testidl.Stub() { @Override public void TestFunction(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { // TODO Auto-generated method stub System.out.println("basicTypes()"); System.err.println("Service"+anInt + "," + aLong + "," + aBoolean + "," + aFloat + "," + aDouble + "," + aString); } }; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub System.out.println("AIDL Service onBind, and return IBinder"); return myStub; } @Override public void onCreate() { // TODO Auto-generated method stub System.out.println("AIDL Service onCreate"); super.onCreate(); } @Override public boolean onUnbind(Intent intent) { // TODO Auto-generated method stub System.out.println("AIDL Service onUnbind"); return super.onUnbind(intent); } @Override public void onDestroy() { // TODO Auto-generated method stub System.out.println("AIDL Service onDestroy"); super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub System.out.println("AIDL Service onStartCommand"); return super.onStartCommand(intent, flags, startId); } }
1 <!-- AndroidManifest.xml 的 application 标签的内容--> 2 <service android:name="myaidlservice"> 3 <intent-filter > 4 <action android:name="zhenshi.mafan.qisia.aidl"/> 5 </intent-filter> 6 </service>
对于客户端,首先需要把aidl文件复制到相应的目录本例中是src/com/example/xxnote/testidl.aidl
package com.example.xxnote.callaidl; import com.example.xxnote.testidl; import android.R.bool; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.view.Menu; import android.view.MenuItem; import android.view.View; public class MainActivity extends Activity { private testidl mytTestidl; private ServiceConnection connection; private boolean isServiceConnected; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); connection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub System.out.println("Client onServiceDisconnected"); } @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub System.out.println("Client onServiceConnected"); mytTestidl = testidl.Stub.asInterface(service); isServiceConnected = true; } }; } @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; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } //关闭服务按钮的事件 public void StopMyService(View v) { System.out.println("StopMyService"); isServiceConnected = false; unbindService(connection); mytTestidl = null; } //开启服务按钮的事件 public void StartMyService(View v) { System.out.println("before bindService()"); bindService( new Intent().setAction("zhenshi.mafan.qisia.aidl"), connection, Context.BIND_AUTO_CREATE); /** * bindService是异步的所以执行bindService方法的同时也开始执行下面的方法了, * Debug跟踪了一下程序发现貌似Activity里面所有的方法都是在主线程的loop()方法 * 循环里面以消息队列里面的一个消息的样子执行的,也就是此处的StartMyService方 * 法对应的消息处理完(此函数返回)后,才能处理下一个消息,即执行onServiceConnected回调方法 * * 试验了一下,StopMyService里面把mytTestidl赋值为null,即每次解除服务绑定后都重置mytTestidl为null * 果然每次下面的语句: * mytTestidl.basicTypes(1, 1, true, 100.0f, 200.0, "ssss"); * 都报空指针异常 */ try { mytTestidl.TestFunction(1, 1, true, 100.0f, 200.0, "ssss"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
这里还有一个需要注意的地方,就是bindService方法 的时候用到的intent,通过setAction可以成功启动服务,用setClassName就不能,不知道什么原因,暂时留待以后解决。
找到原因了,用setClassName的时候必须使用全限定类名,如:new Intent().setClassName("com.example.client.callaidl", "com.example.client.callaidl.testact")