一个简单的demo学习Android远程Service(AIDL的使用)
作者:milo发布:2012-08-28 13:01分类:潜技术阅读:2,185次评论:1条评论
这是milo很早之前写在论坛上的一个帖子,现在整理出来,milo也复习一下
一般来说Android 的四大组件都是运行在同一个进程中的,但远程Service运行在不同的进程里。这进程间的通信是使用了Android Binder机制。Android 中Service 有本地Service和远程Service之分,本地Service用法比较简单,而远程Service用法稍微要复杂一些。下面就是一个使用AIDL的用法。
AIDL即android 接口定义语言,概念不多说,网上有太多的帖子介绍概念。本文只想说明一下aidl的用法。由于最近开发一个播放器的项目使用了aidl。aidl是解决进程间通信用的。在本例中就是Activity(即client端)与Service(即服务端)的通信。
首先,定义Aidl文件,如Service中暴露给Activity的接口可以定义在aidl文件中,反之也一样。本文中,Service给Activity使用接口文件是ServiceAIDL.aidl
1 2 3 4 5 6 7 8 9 10 11 12
|
package com.miloisbadboy.aidl; import com.miloisbadboy.aidl.ActivityAIDL; /** *Service中暴露给Activity的接口可以定义在aidl文件中 */ interface ServiceAIDL{ void callService(); /** *在Activity中注册ActivityAIDL到Service中,使Service中可以调用ActivityAIDL中的方法 **/ void registActivityCallBack(ActivityAIDL callBack); } |
Activity给Service中使用的ActivityAIDL.aidl
1 2 3 4 5 6 7
|
package com.miloisbadboy.aidl; /** *Activity中暴露给Service的接口可以定义在aidl文件中 */ interface ActivityAIDL{ void callActivity(); } |
上面两个aidl在会自动在gen目录下生成对应的java文件。
第二步,写Service。写一个MyService继承于Service类,并在onBind()方法中 返回ServiceAidl.Stub对象
具体看下面代码
MyService.java
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
|
package com.miloisbadboy; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.widget.Toast; import com.miloisbadboy.aidl.ActivityAIDL; import com.miloisbadboy.aidl.ServiceAIDL; /** * 远程服务 */ public class MyService extends Service { public static final String SERVICE_NAME = "com.miloisbadboy.start.MyService"; public static final String TAG = "MyService"; private ActivityAIDL activityAIDL; @Override public IBinder onBind(Intent intent) { return mBinder; } private ServiceAIDL.Stub mBinder = new ServiceAIDL.Stub() { @Override public void callService() throws RemoteException { Log.i(TAG, "Activity Call Service's method ****** callService()"); Toast.makeText(getApplicationContext(), "Call Service's method ****** callService()", 1000).show(); activityAIDL.callActivity(); } @Override public void registActivityCallBack(ActivityAIDL callBack) throws RemoteException { activityAIDL = callBack; } }; } |
MyService中有ActiviyAIDL的一个引用,此类型的实例是在ServiceAIDL.Stud这个代理中得到的,即是在registActivityCallBack(ActivityAIDL callBack)方法中对其赋值,这个方法是在Activity中将ActivityAIDL的接口注册到Service中去的。
在ServiceAidl.Stub mBinder = new ServiceAidl.Stub(){}里面的callService() 和registActivityAidl(ActivityAidl activityAidl)方法就是在Activity将会被调用到的。
最后看一个Activity类
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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
package com.miloisbadboy; 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.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; import com.miloisbadboy.aidl.ActivityAIDL; import com.miloisbadboy.aidl.ServiceAIDL; /** * 测试远程Service */ public class TestAIDLActivity extends Activity implements OnClickListener{ private static final String TAG = "TestAIDLActivity"; private Button start; private Button stop; private Button callService; /** * service call back */ private ServiceAIDL serviceAIDL; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); start = (Button)findViewById(R.id.start_service); stop = (Button)findViewById(R.id.stop_service); callService = (Button)findViewById(R.id.call_service); start.setOnClickListener(this); stop.setOnClickListener(this); callService.setOnClickListener(this); } @Override public void onClick(View v) { if(v == start){ Intent service = new Intent(MyService.SERVICE_NAME); //绑定Service 并将ServiceConnection的实例传入 bindService(service, serviceConn, Context.BIND_AUTO_CREATE); stop.setVisibility(View.VISIBLE); }else if(v == stop){ unbindService(serviceConn); }else{ try { if(serviceAIDL!=null){ serviceAIDL.callService(); }else { Toast.makeText(this, "Service is not started!", 1000).show(); } } catch (RemoteException e) { e.printStackTrace(); } } } private ServiceConnection serviceConn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { serviceAIDL = null; Toast.makeText(getApplication(), "Service is unbind!", 1000).show(); } @Override public void onServiceConnected(ComponentName name, IBinder service) { serviceAIDL = ServiceAIDL.Stub.asInterface(service); //在此将Activity暴露给Service的接口实现注册到Service中去 try { serviceAIDL.registActivityCallBack(activityAidl); } catch (RemoteException e) { e.printStackTrace(); } } }; /** * 在activity中实现ActivityAIDL接口 */ private ActivityAIDL activityAidl = new ActivityAIDL.Stub() { @Override public void callActivity() throws RemoteException { Log.i(TAG, "callActivity()"); Toast.makeText(getApplicationContext(), "service call activity", 1000).show(); } }; } |
在activity中有三个按钮分别为 start service ; stop service ;callService
各个按钮的动作顾名思义啦。特别注意到。在Activity ServiceConnection中 会通过ServiceAIDL.Stub.asInterface(service)得到ServiceAIDL的实例,并且将activityAidl的引用注册到了Service中。
在start service 按钮事件里,通过bindService(service, serviceConn, Context.BIND_AUTO_CREATE)将Service 与Activity绑定。
这个程序跑起来的顺序是,启动Activity后,并start service后 点击callServiceBtn,就会调用MyService中实现的callService()接口,而在callService中又调用了activityAidl即Activity的回调callActivity()方法
这样就模拟了 Activity 与Service两个进程间的通信,即相互调用了对方的对象。
本文只是对Aidl的用法做了一个小小总结,算是抛砖引玉吧。