Android中程序与Service交互的方式(二)-五种交互方式
1. 广播交互
提到Activity与Service的交互,可能狠多人首先想到的就是BroadCast——广播。在Android中,广播是系统提供的一种很好的交互方式。比如:在电池电量过低,开机完成等情况下,系统都会发出相应的系统广播,我们的应用程序只需要注册相应的广播接收器,就可以接收到这些系统的广播。同时,我们也可以定义自己的广播,这样在不同的Activity、Service以及应用程序之间,就可以通过广播来实现交互。我们通过模拟应用程序后台下载的情况来分析Service与Activity的交互方式。实现效果如图1.1:
图1.1
当我们点击StartService按钮之后,界面上的进度条将会每隔一秒加1。因为是模拟下载,因此下载动作我们在Service中通过一个Timer定时器来实现,在Timer中对一个整型数据i进行自加(i++),然后Client端获取Server端的i值并显示在界面上,从而达到模拟的目的。
1.1. 实现原理
Server端将目前的下载进度,通过广播的方式发送出来,Client端注册此广播的监听器,当获取到该广播后,将广播中当前的下载进度解析出来并更新到界面上。
1.2. 实现步骤
1.2.1 在Client端中通过startService()啟动Service。
[java] view plain copy
- if(v==startBtn){
- Log.i(TAG,"startbuttonclicked...pid:"+Process.myPid());
- mIntent.setClass(BroadCastService.this,DownLoadService.class);
- startService(mIntent);
- }
1.2.2 DownLoadService接到启动的命令之后,执行onCreate()方法,并在其中开启timer计数模拟下载。
[java] view plain copy
- @Override
- publicvoidonCreate(){
- super.onCreate();
- Log.i(TAG,"DownLoadService.onCreate()...pid:"+Process.myPid());
- intent=newIntent("com.seven.broadcast");
- mTimer=newTimer();
- mTimer.schedule(newMyTimerTask(),0,TIME*1000);
- }
1.2.3 在Server端的timer计数其中发送广播,告知Client端目前下载进度。
[java] view plain copy
- classMyTimerTaskextendsTimerTask{
- @Override
- publicvoidrun(){
- if(i==100){
- i=0;
- }
- intent.putExtra("CurrentLoading",i);
- sendBroadcast(intent);
- i++;
- Log.e(TAG,"i="+i);
- }
- }
1.2.4 在Client端通过匿名内部类的方式实例化BroadcastReceiver并覆写其中的onReceive()方法。
[java] view plain copy
- BroadcastReceiverreceiver=newBroadcastReceiver(){
- @Override
- publicvoidonReceive(Contextcontext,Intentintent){
- if(MYACTION.equals(intent.getAction())){
- Log.i(TAG,"getthebroadcastfromDownLoadService...");
- curLoad=intent.getIntExtra("CurrentLoading",ERROR);
- mHandler.sendMessage(mHandler.obtainMessage());
- }
- }
- };
1.2.5 更新主介面下载进度。
[java] view plain copy
- HandlermHandler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemsg){
- super.handleMessage(msg);
- Log.i(TAG,"currentloading:"+curLoad);
- if(curLoad<0||curLoad>100){
- Log.e(TAG,"ERROR:"+curLoad);
- return;
- }
- mProgressBar.setProgress(curLoad);
- mTextView.setText(curLoad+"%");
- }
- };
1.2.6 一定要对Broadcast进行注册和取消注册。只有注册之后相应的broadcast之后才能接收到广播注册方法有两种。
动态注册/取消注册:
[java] view plain copy
- @Override
- protectedvoidonResume(){
- super.onResume();
- Log.i(TAG,"registerthebroadcastreceiver...");
- IntentFilterfilter=newIntentFilter();
- filter.addAction(MYACTION);
- registerReceiver(receiver,filter);
- }
- @Override
- protectedvoidonDestroy(){
- super.onDestroy();
- Log.i(TAG,"unregisterthebroadcastreceiver...");
- unregisterReceiver(receiver);
- }
静态註册:
[html] view plain copy
- <receiverandroid:name="MyBroadcastReceiver">
- <intent-filter>
- <actionandroid:name="com.seven.broadcast"/>
- </intent-filter>
- </receiver>
最后贴出整个AndroidManifest.xml文件
[html] view plain copy
- <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
- <activityandroid:name=".BroadCastService"
- android:label="@string/app_name">
- <intent-filter>
- <actionandroid:name="android.intent.action.MAIN"/>
- <categoryandroid:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- <serviceandroid:name="DownLoadService"android:process=":remote"/>
- </application>
1.3 小结
通过广播的方式实现Activity与Service的交互操作简单且容易实现,可以胜任简单级的应用。但缺点也十分明显,发送广播受到系统制约。系统会优先发送系统级广播,在某些特定的情况下,我们自定义的广播可能会延迟。同时在广播接收器中不能处理长耗时操作,否则系统会出现ANR即应用程序无响应。
2. 共享文件交互
这里提到的共享文件指的是Activity和Service使用同一个文件来达到传递数据的目的。我们使用SharedPreferences来实现共享,当然也可以使用其它IO方法实现,通过这种方式实现交互时需要注意,对于文件的读写的时候,同一时间只能一方读一方写,不能两方同时写。实现效果如图2.1:
图2.1
2.1 实现原理
Server端将当前下载进度写入共享文件中,Client端通过读取共享文件中的下载进度,并更新到主界面上。
2.2 实现步骤
2.2.1 在Client端通过startService()啟动Service。
[java] view plain copy
- if(startSerBtn==v){
- Log.i(TAG,"StartButtonClicked.");
- if(intent!=null){
- startService(intent);
- timer.schedule(newMyTimerTask(),0,TIME*1000);
- }
- }
2.2.2 Server端收到启动intent之后执行onCreate()方法,并开启timer,模拟下载,以及初始化SharedPreferences对象preferences。
[java] view plain copy
- @Override
- publicvoidonCreate(){
- super.onCreate();
- Log.i(TAG,"DownLoadService.onCreate()...");
- preferences=getSharedPreferences("CurrentLoading_SharedPs",0);
- timer=newTimer();
- timer.schedule(newMyTimerTask(),0,TIME*1000);
- }
2.2.3 开始计数并将下载进度写入shared_prefs文件夹下的xml文件中,内容以键值对的方式保存。
- classMyTimerTaskextendsTimerTask{
- @Override
- publicvoidrun(){
- setCurrentLoading();
- if(100==i){
- i=0;
- }
- i++;
- }
- }
- privatevoidsetCurrentLoading(){
- preferences.edit().putInt("CurrentLoading",i).commit();
- }
首先,使用sharedPreferences前需要获取文件引用。
preferences = getSharedPreferences("CurrentLoading_SharedPs", 0);
其次,使用sharedpreferences写数据方式。
preferences.edit().putInt("CurrentLoading", i).commit();
最后,读取数据的方式。
int couLoad = preferences.getInt("CurrentLoading", 0);
2.2.4 Client端通过读取/data/data/com.seven.servicetestdemo/shared_prefs文件夹下的xml文件,并取得里面的键值对,从而获取到当前的下载进度,并更新到主界面上。
[java] view plain copy
- HandlermHandler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemsg){
- super.handleMessage(msg);
- intcouLoad=preferences.getInt("CurrentLoading",0);
- mProgressBar.setProgress(couLoad);
- currentTv.setText(couLoad+"%");
- }
- };
2.3 小结
因為方法简单,因此就不贴出AndroidManifest.xml文件了。对於这种方式实现Activity与Service的交互,可以说很方便,就像使用管道,一个往裡写,一个往外读。但这种方式也有缺陷,写入数据较为复杂以及数据量较大时,就有可能导致写入与读数据出不一致的错误。同时因为经过了一个中转站,这种操作将更耗时。
3. Messenger交互(信使交互)
Messenger翻译过来指的是信使,它引用了一个Handler对象,别人能够向它发送消息(使用mMessenger.send(Message msg)方法)。该类允许跨进程间基于Message通信,在服务端使用Handler创建一个 Messenger,客户端只要获得这个服务端的Messenger对象就可以与服务端通信了。也就是说我们可以把Messenger当做Client端与Server端的传话筒,这样就可以沟通交流了。实现效果如图3.1:
图3.1
3.1 实现原理
在Server端与Client端之间通过一个Messenger对象来传递消息,该对象类似于信息中转站,所有信息通过该对象携带。
3.2 Messenger的一般用法
(1). 在Server端创建信使对象。
mMessenger = new Messenger(mHandler)
(2). Client端使用bindService()绑定Server端。
(3). Server端的onBind()方法返回一个binder对象。
return mMessenger.getBinder();
(4). Client端使用返回的binder对象得到Server端信使。
[java] view plain copy
- publicvoidonServiceConnected(ComponentNamename,IBinderservice){
- rMessenger=newMessenger(service);
- ......
- }
[java] view plain copy
- publicMessenger(IBindertarget){mTarget=IMessenger.Stub.asInterface(target);}
(5). Client端可以使用这个Server端的信使对象向Server端发送消息。
rMessenger.send(msg);
这样Server端的Handler对象就能收到消息了,然后可以在其handlerMessage(Message msg)方法中进行处理。经过这5个步骤之后只有Client端向Server端发送消息,这样的消息传递是单向的,那么如何实现消息的双向传递呢?
首先需要在第5步做修改,在send(msg)前通过msm.replyTo = mMessenger将Client端自己的信使设置到消息中,这样Server端接收到消息时同时也得到了Client端的信使对象,然后Server端也可以通过使用得到的Client端的信使对象来项Client端发送消息 cMessenger = msg.replyTo2 cMessenger.send(message);
这样即完成了从Server端向Client端发送消息的功能,这样Client端可以在自己的Handler对象的handlerMessage()方法中接收服务端发送来的message进行处理。
3.3 实现步骤
3.3.1 创建并初始化Server端的信使对象。
[java] view plain copy
- privateHandlermHandler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemsg){
- super.handleMessage(msg);
- switch(msg.what){
- caseTEST:
- Log.e(TAG,"GetMessagefromMainActivity.");
- cMessenger=msg.replyTo;
- mTimer.schedule(newMyTimerTask(),1000,TIME*1000);
- break;
- default:
- break;
- }
- }
- };
- //It'sthemessengerofserver
- privateMessengermMessenger=newMessenger(mHandler);
3.3.2 在Client端使用bindService()方法绑定Server端。
[java] view plain copy
- privatevoiddoBindService(){
- Log.i(TAG,"doBindService()...");
- mIsBind=bindService(intent,serConn,BIND_AUTO_CREATE);//ifbindsuccessreturntrue
- Log.e(TAG,"Isbind:"+mIsBind);
- }
3.3.3 在Server端的onBind()方法中返回一个binder对象。
[java] view plain copy
- @Override
- publicIBinderonBind(Intentintent){
- Log.i(TAG,"MessengerService.onBind()...");
- returnmMessenger.getBinder();
- }
3.3.4 Client端使用ServiceConnected()方法来获取Server端的信使对象。
[java] view plain copy
- privateServiceConnectionserConn=newServiceConnection(){
- @Override
- publicvoidonServiceDisconnected(ComponentNamename){
- Log.i(TAG,"onServiceDisconnected()...");
- rMessenger=null;
- }
- @Override
- publicvoidonServiceConnected(ComponentNamename,IBinderservice){
- Log.i(TAG,"onServiceConnected()...");
- rMessenger=newMessenger(service);//gettheobjectofremoteservice
- mMessenger=newMessenger(mHandler);//initialtheobjectoflocalservice
- sendMessage();
- }
- };
3.3.5 Client端使用获取到的rMessenger来发送消息给Server端,同时将Client端的信使封装到消息中,一并发送给Server端。
[java] view plain copy
- privatevoidsendMessage(){
- Messagemsg=Message.obtain(null,MessengerService.TEST);//MessengerService.TEST=0
- msg.replyTo=mMessenger;
- try{
- rMessenger.send(msg);
- }catch(RemoteExceptione){
- e.printStackTrace();
- }
- }
3.3.6 Server端获取Client端发送的消息并得到Client端的信使对象。
[java] view plain copy
- privateHandlermHandler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemsg){
- super.handleMessage(msg);
- switch(msg.what){
- caseTEST:
- Log.e(TAG,"GetMessagefromMainActivity.");
- cMessenger=msg.replyTo;//getthemessengerofclient
- mTimer.schedule(newMyTimerTask(),1000,TIME*1000);
- break;
- default:
- break;
- }
- }
- };
3.3.7 Server端向Client端发送数据。
[java] view plain copy
- classMyTimerTaskextendsTimerTask{
- @Override
- publicvoidrun(){
- if(i==100){
- i=0;
- }
- try{
- //sendthemessagetotheclient
- Messagemessage=Message.obtain(null,MessengerService.TEST,i,0);
- cMessenger.send(message);
- }catch(RemoteExceptione){
- e.printStackTrace();
- }
- i++;
- }
- }
3.3.8 Client端接收来自Server端的数据。
- privateHandlermHandler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemsg){
- super.handleMessage(msg);
- switch(msg.what){
- caseMessengerService.TEST:
- Log.e(TAG,"GetMessageFromMessengerService.i="+msg.arg1);
- intcurLoad=msg.arg1;
- mTextView.setText(curLoad+"%");
- mProgressBar.setProgress(curLoad);
- break;
- default:
- break;
- }
- }
- };
以下是AndroidManifest.xml文件:
[html] view plain copy
- <?xmlversion="1.0"encoding="utf-8"?>
- <manifestxmlns:android="http://schemas.android.com/apk/res/android"
- package="com.seven.messengerservicedemo"
- android:versionCode="1"
- android:versionName="1.0">
- <uses-sdkandroid:minSdkVersion="10"/>
- <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
- <activityandroid:name=".MainActivity"
- android:label="@string/app_name">
- <intent-filter>
- <actionandroid:name="android.intent.action.MAIN"/>
- <categoryandroid:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- <serviceandroid:name="MessengerService">
- <intent-filter>
- <actionndroid:name="com.seven.messagerservice.MessengerService"/>
- </intent-filter>
- </service>
- </application>
- </manifest>
3.4 小结
通过Messenger来实现Activity和Service的交互,稍微深入一点我们就可以知道,其实Messenger也是通过AIDL来实现的。对於前两种实现方式,Messenger方式总体上来讲也是比较容易理解的,这就和平时使用Handler和Thread通信一个道理。
4. 自定义接口交互
何谓自定义接口呢,其实就是我们自己通过接口的实现来达到Activity与Service交互的目的,我们通过在Activity和Service之间架设一座桥樑,从而达到数据交互的目的,而这种实现方式和AIDL非常类似(后文会说到)。实现效果如图4.1:
图4.1
4.1 实现原理
自定义一个接口,该接口中有一个获取当前下载进度的空方法。Server端用一个类继承自Binder并实现该接口,覆写了其中获取当前下载进度的方法。Client端通过ServiceConnection获取到该类的对象,从而能够使用该获取当前下载进度的方法,最终实现实时交互。
4.2 实现步骤
4.2.1 新建一个Interface,并在其中创建一个用于获取当前下载进度的的空方法getCurrentLoad()。
[java] view plain copy
- packagecom.seven.servicetestdemo;
- publicinterfaceICountService{
- publicintgetCurrentLoad();
- }
4.2.2 新建Server端DownService实现ICountService并在其中通过一个内部类ServiceBinder继承自Binder并实现ICoutService接口。
[java] view plain copy
- publicclassDownLoadServiceextendsServiceimplementsICountService{
- privateServiceBinderserviceBinder=newServiceBinder();
- publicclassServiceBinderextendsBinderimplementsICountService{
- @Override
- publicintgetCurrentLoad(){
- Log.i(TAG,"ServiceBindergetCurrentLoad()...i=:"+i);
- returni;
- }
- }
- @Override
- publicintgetCurrentLoad(){
- return0;
- }
- }
4.2.3 Client端使用bindService()绑定Server端。
[java] view plain copy
- if(startSerBtn==v){
- Log.i(TAG,"StartButtonClicked.");
- bindService(intent,serConn,BIND_AUTO_CREATE);
- timer.schedule(newMyTimerTask(),1000,TIME*1000);//这里一定要延迟一下再开始获取数据,不然会报空指针异常
- }
4.2.4 Server端返回binder对象。
[java] view plain copy
- @Override
- publicIBinderonBind(Intentintent){
- Log.i(TAG,"DownLoadService.onBind()...");
- returnserviceBinder;
- }
4.2.5 Client端通过ServiceConnection来获取Server端的binder对象。
[java] view plain copy
- privateServiceConnectionserConn=newServiceConnection(){
- @Override
- publicvoidonServiceDisconnected(ComponentNamename){
- iCountService=null;
- }
- @Override
- publicvoidonServiceConnected(ComponentNamename,IBinderservice){
- Log.i(TAG,"onServiceConnected()...");
- iCountService=(ICountService)service;
- }
- };
4.2.6 在绑定完成之后,Server端会开启下载,在实际情况中Server端会开启独立线程用于下载,这里用i++来代替。
[java] view plain copy
- @Override
- publicvoidonCreate(){
- super.onCreate();
- Log.i(TAG,"DownLoadService.onCreate()...");
- timer=newTimer();
- timer.schedule(newMyTimerTask(),0,TIME*1000);
- }
- classMyTimerTaskextendsTimerTask{
- @Override
- publicvoidrun(){
- if(100==i){
- i=0;
- }
- i++;
- }
- }
4.2.7 Server端已经开启了下载,那么Client端需要及时获取下载进度并在主界面上更新。
[java] view plain copy
- HandlermHandler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemsg){
- super.handleMessage(msg);
- Log.i(TAG,"handleMessage...");
- intcurLoad=iCountService.getCurrentLoad();
- mProgressBar.setProgress(curLoad);
- currentTv.setText(curLoad+"%");
- }
- };
- classMyTimerTaskextendsTimerTask{
- @Override
- publicvoidrun(){
- mHandler.sendMessage(mHandler.obtainMessage());
- }
- }
4.3 小结
通过上面的例子可以知道,这种方法简单实用,扩展性强,但其也有一些缺点,比如需要延迟一些再开始获取Server端的数据,从而无法完全实现从零开始同步更新。综其所述,通过自定义接口实现Activity与Service交互的方法还是比较实用的。适用於同进程中通信,不能进行跨进程通信。
5. AIDL交互
什么是AIDL?
AIDL是Android Interface Definition Language的首字母缩写, 也就是Android接口定义语言。提及AIDL就不得不说下Android的服务,Android 支持两种服务类型的服务即本地服务和远程服务。
本地服务无法供在设备上运行的其他应用程序访问,也就是说只能该应用程序内部调用,比如某些应用程序中的下载类服务,这些服务只能由内部调用。而对于远程服务,除了可以由本应用程序调用,还可以允许其他应用程序访问。远程服务一般通过AIDL来实现,可以进行进程间通信,这种服务也就是远程服务。
本地服务与远程服务还是有一些重要的区别。具体来讲,如果服务完全只供同一进程中的组件使用(运行后台任务),客户端一边通过调用 Context.startService()来启动该服务。这种类型的服务为本地服务,它的一般用途是后台执行长耗时操作。而远程服务一般通过bindService()方法启动,主要为不同进程间通信。我们也将远程服务称为AIDL支持服务,因为客户端使用 AIDL 与服务通信。Android中对于远程服务有多种叫法:远程服务、AIDL服务、外部服务和RPC服务。
5.1 AIDL实现流程图
图5.1
这属于代理/存根结构,通过这张AIDL的流程图,很容易发现Android实现IPC其实是在原来的C/S框架上加入了代理/存根结构。
比如,你到自动取款机上去取款。那么你就是客户(Client),取款机就是你的代理(Proxy);你不会在乎钱具体放在那里,你只想将你的钱从取款机中取出来。你同银行之间的操作完全是取款机代理实现。你的取款请求通过取款机传到另一边,即银行的服务器(Server)。它也没有必要知道你在哪儿取钱,它所关心的是你的身份和你取款多少。当它确认你的权限,就进行相应的操作,返回操作结果给取款机,取款机根据服务器返回结果,从保险柜里取出相应数量的钱给你。你取出卡后,操作完成。取款机不是直接同服务器连接的,他们之间还有一个“存根(Stub)”,取款机与存根通信,服务器与存根通信,从某种意义上说存根就是服务器的代理。实现效果如图5.2:
图5.2
5.3 实现原理
AIDL属于Android的IPC机制,常用于跨进程通信,主要实现原理基于底层Binder机制。
5.4 实现步骤
5.4.1 建立工程。按照图5.3和图5.4建立AIDLServer端以及AIDLClient端。在AIDLServer端中只有一个服务程序,没有主界面,其主要功能就是负责下载。AIDLClient端从AIDLServer端获取当前下载进度(注:AIDLServer端和AIDLClient端是不同的两个APK,在模拟本例的时候,需要先在模拟器上安装AIDLServer编译出来的APK,安装方法可以直接在模拟器上运行一次,可以通过adb install your.apk 来安装)。
图5.3
AIDLServer端中新建了一个ICountService.aidl的文件,该文件内容如下:
[plain] view plain copy
- packagecom.seven.aidlserver;
- interfaceICountService{
- intgetCount();
- }
aidl文件的书写规范如下:
(1). Android支持String和CharSequence(以及Java的基本数据类型);
(2). 如果需要在aidl中使用其它aidl接口类型,需要import,即使是在相同包结构下;
(3). Android允许传递实现Parcelable接口的类,需要import;
(4). Android支持集合接口类型List和Map,但是有一些限制,元素必须是基本型或者前面三种情况,不需要import集合接口类,但是需要对元素涉及到的类型import;
(5). 非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。
图5.4
AIDLClient端需要将AIDLServer端的ICountService.aidl文件复製过去,这裡为了方便,新建了一个和Server端同名的包,并将ICountService.aidl放与其中。
5.4.2 我们在Server端建立好ICoutService.aidl文件之后,Eclipse会在/gen/com.seven.aidlserver/目录下自动生成ICountService.java文件。该文件由Eclipse自动生成,请勿随便修改,后文我们需引用到的内容如下:
[java] view plain copy
- publicstaticcom.seven.aidlserver.ICountServiceasInterface(android.os.IBinderobj){
- if((obj==null)){
- returnnull;
- }
- android.os.IInterfaceiin=(android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
- if(((iin!=null)&&(iininstanceofcom.seven.aidlserver.ICountService))){
- return((com.seven.aidlserver.ICountService)iin);
- }
- returnnewcom.seven.aidlserver.ICountService.Stub.Proxy(obj);
- }
5.4.3 在Server端新建一个内部类继承自ICountService.Stub并覆写其中的getCount()方法,以及实例化该类的一个对象serviceBinder。
[java] view plain copy
- privateAIDLServerBinderserviceBinder=newAIDLServerBinder();
- classAIDLServerBinderextendsICountService.Stub{
- @Override
- publicintgetCount()throwsRemoteException{
- returni;
- }
- }
5.4.4 在Server端的onBind()方法中,返回前面的serviceBinder对象。
[java] view plain copy
- @Override
- publicIBinderonBind(Intentintent){
- Log.i(TAG,"AIDLServer.onBind()...");
- returnserviceBinder;
- }
5.4.5 在Server端的onCreate()方法中,开启timer,模拟下载。在Client端通过bindService()绑定Server端的时候,会首先执行Server端的onCreate()方法。
- @Override
- publicvoidonCreate(){
- super.onCreate();
- Log.i(TAG,"AIDLServer.onCreate()...");
- mTimer=newTimer();
- mTimer.schedule(newMyTimerTask(),0,TIME*1000);
- }
- classMyTimerTaskextendsTimerTask{
- @Override
- publicvoidrun(){
- if(i==100){
- i=0;
- }
- i++;
- }
- }
5.4.6 Client端通过bindService()绑定Server端。
- if(startBtn==v){
- Log.i(TAG,"startbuttonclick.");
- mIsBind=bindService(intent,serConn,BIND_AUTO_CREATE);
- mTimer.schedule(newMyTimerTask(),1000,TIME*1000);
- }
5.4.7 Client端通过ServiceConnection来获取Server端的binder对象。
[java] view plain copy
- privateServiceConnectionserConn=newServiceConnection(){
- @Override
- publicvoidonServiceDisconnected(ComponentNamename){
- iCountService=null;
- }
- @Override
- publicvoidonServiceConnected(ComponentNamename,IBinderservice){
- Log.i(TAG,"AIDLClient.onServiceConnected()...");
- iCountService=ICountService.Stub.asInterface(service);
- }
- };
5.4.8 获取当前下载进度并更新到界面上。
[java] view plain copy
- HandlermHandler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemsg){
- super.handleMessage(msg);
- try{
- intcount=iCountService.getCount();
- mTextView.setText(count+"%");
- mProgressBar.setProgress(count);
- }catch(RemoteExceptione){
- e.printStackTrace();
- }
- }
- };
5.5 小结
AIDL在Android中是进程间通信常用的方式,可能使用较為复杂,但效率高,扩展性好。同时很多系统服务就是以这种方式完成与应用程序通信的。
本文通过五个例子,分别介绍了五种与Service交互的方法,这些方法有的简单,有的可能要复杂一些。在这里只是做为对Servie的一些总结。后文附上源码下载链接,不需要积分的哦。
源码下载
所有源码均在Ubuntu 10.04 Eclipse-Indigo下实验通过 模拟器采用的是2.3的镜像。
更多相关文章
- 浅谈Java中Collections.sort对List排序的两种方法
- 类和 Json对象
- Python list sort方法的具体使用
- python list.sort()根据多个关键字排序的方法实现
- Android(安卓)WebView与JavaScript交互实现Web App
- Android的消息机制
- Android处理输入事件的流程(一)
- Android(安卓)AIDL Service调试方法
- android与javascript交互调用