Android综合揭秘——全面剖释Service服务
引言
Service服务是Android系统最常用的四大部件之一,Android支持Service服务的原因主要目的有两个,一是简化后台任务的实现,二是实现在同一台设备当中跨进程的远程信息通信。 Service服务主要分为LocalService本地服务与RemoteService远程服务两种,本地服务只支持同一进程内的应用程序进行访问,远程服务可通过AIDL(AndroidInterfaceDefinitionLanguage)技术支持跨进程访问。服务可以通过Context.startService()和Context.bindService()进行启动,一般LocalService本地服务可使用其中一种方法启动,但RemoteService远程服务只能使用Context.bindService()启动,而两种调用方式在使用场景与活动流程中都存在差异。还有通过多线程技术处理Service服务的延时操作等技术,下文将针对Android系统的Service服务的一系列操作进行深入探讨。
一、AndroidService的概念与说明
1.1Service服务的定义
AndroidService是Android平台最常用的部件之一,其概念与WindowsService类似,熟悉Windows开发的朋友应该对此概念会有所了解。当Android系统需要对现有的程序数据进行监听,或者对现有Actitvity提供数据服务支撑时,就会使用到AndroidService。例如:对用户地理位置的检测,对SD卡定时扫描,对当地气候的定期检测都会使用到Service服务,Service一般都是运行于后台,不需要用户界面支撑。Service服务不会自动创建线程,如果开发人员没有为Service服务添加异步操作,那Service服务将运行于主线程当中。
1.2Service服务的类型
1.2.1按照Service的生命周期模型一共分为两种类型
第一类是直接通过Context.startService()启动,通过Context.stopService()结束Service,其特点在于调用简单,方便控制。缺点在于一旦启动了Service服务,除了再次调用或结束服务外就再无法对服务内部状态进行操控,缺乏灵活性。
第二类是通过Context.bindService()启动,通过Context.unbindService()结束,相对其特点在运用灵活,可以通过IBinder接口中获取Service的句柄,对Service状态进行检测。
从Android系统设计的架构上看,startService()是用于启动本地服务,bindService()更多是用于对远程服务进行绑定。当然,也可以结合两者进行混合式应用,先通过startService()启动服务,然后通过bindService()、unbindService()方法进行多次绑定,以获取Service服务在不同状态下的信息,最后通过stopService()方法结束Service运行,在下面文章里将举例一一说明。
1.2.2按照Service的寄存方式分为两种类型
本地服务(LocalService)寄存于当前的进程当中,当前进程结束后Service也会随之结束,Service可以随时与Activity等多个部件进行信息交换。Service服务不会自动启动线程,如果没有人工调用多线程方式进行启动,Service将寄存于主线程当中。
远程服务(RemoteService)独立寄存于另一进程中,通过AIDL(AndroidInterfaceDefinitionLanguage)接口定义语言,实现Android设备上的两个进程间通信(IPC)。AIDL的IPC机制是基于RPC(RemoteProceduceCall)远程过程调用协议建立的,用于约束两个进程间的通讯规则,供编译器生成代码。进程之间的通信信息,首先会被转换成AIDL协议消息,然后发送给对方,对方收到AIDL协议消息后再转换成相应的对象,其使用方法在下文将会详细说明。
回到目录
二、AndroidService的生命周期
2.1Service服务的常用方法
方法 说明 voidonCreate() 当Service被启动时被触发,无论使用Context.startServcie还是Context.bindService启动服务,在Service整个生命周期内只会被触发一次 intonStartCommand(Intentintent,intflags,intstartId) 当通过Context.startService启动服务时将触发此方法,但当使用Context.bindService方法时不会触发此方法,其中参数intent是startCommand的输入对象,参数flags代表service的启动方式,参数startId当前启动service的唯一标式符。返回值决定服务结束后的处理方式,下文将再作详细说明。 voidonStart(Intentintent,intstartId) 2.0旧版本的方法,已被Android抛弃,不推荐使用,默认在onStartCommand执行中会调用此方法 IBinderonBind(Intentintent) 使用Context.bindService触发服务时将调用此方法,返回一个IBinder对象,在远程服务时可用于对Service对象进行远程操控 voidonRebind(Intentintent) 当使用startService启动Service,调用bindService启动Service,且onUnbind返回值为true时,下次再次调用Context.bindService将触发方法 booleanonUnbind(Intentintent) 调用Context.unbindService触发此方法,默认返回false,当返回值true后,再次调用Context.bindService时将触发onRebind方法 voidonDestory() 分三种情况:1.以Context.startService启动service,调用Context.stopService结束时触发此方法;2.以Context.bindService启动service,以Context.unbindService结束时触发此方法;3.先以Context.startService启动服务,再用Context.bindService绑定服务,结束时必须先调用Context.unbindService解绑再使用Context.stopService结束service才会触发此方法。 表2.1
细说onStartCommand方法 由于手机的RAM、内部资源有限,所以很多Service都会因为资源不足而被Kill掉,这时候返回值就决定了Service被Kill后的处理方式,一般intonStartCommand(intent,flags,startId)的返回值分为以下几种:
START_STICKY 如果service进程被kill掉,系统会尝试重新创建Service,如果在此期间没有任何启动命令被传递到Service,那么参数intent将为null。
START_NOT_STICKY 使用这个返回值时,如果在执行完onStartCommand()后,服务被异常kill掉,系统不会自动重启该服务。
START_REDELIVER_INTENT 使用这个返回值时,如果在执行完onStartCommand()后,服务被异常kill掉,系统会自动重启该服务,并将intent的值传入。
START_STICKY_COMPATIBILITY START_STICKY的兼容版本,但不保证服务被kill后一定能重启。 而输入参数flags正是代表此次onStartCommand()方法的启动方式,正常启动时,flags默认为0,被kill后重新启动,参数分为以下两种:
START_FLAG_RETRY 代表service被kill后重新启动,由于上次返回值为START_STICKY,所以参数intent为null
START_FLAG_REDELIVERY 代表service被kill后重新启动,由于上次返回值为START_REDELIVER_INTENT,所以带输入参数intent
2.2Service的运作流程
上文曾经提到Service的启动方法有Context.startService(intent),Context.bindService(intent,serviceConnection,int)两种,下面详细介绍一下它们工作流程。
当系统调用Context.startService()方法时,先会触发Service的onCreate()方法,这一般用于对Service的运行条件作初始化处理,且在Service的生命周期内只会被触发一次。然后系统将触发Service的onStartCommand()方法,用户每次调用startService()方法,都会触发onStartCommand()方法。之后,Service除非在资源不足的情况下被系统kill掉,否则Service不会自动结束,直至系统调用Context.stopService()方法时,Service才会结束。在Service结束时将自动启动onDestory()方法对运转中的Service作最后处理。
注意:即使系统多次调用startService()或bindService()方法,onCreate()方法只会在第一次调用时被触发。同理onDestory()方法也只会在服务完结时被触发,其原理可看第2.1节该方法的详细说明。
当系统调用Context.bindService()方法时,也会触发Service的onCreate()方法对Service对象的运行条件作初始化处理,然后触发Service的onBind()方法对服务进行绑定,成功获取Service的句柄后,系统就会通过用户自定义的serviceConnection对象onServiceConnected(ComponentNamename,IBinderservice)方法,对Service对象作出处理。最后当系统调用Context.unbindService()结束服务时,就会激发Service的onDestory()方法对运转中的Service作最后的处理。
注意:系统调用Context.bindService()方法,完成Service.onBind()绑定后就会触发serviceConnection对象的onServiceConnected()方法,但只要系统未使用Context.unbindService()方法对service服务进行解绑,即使多次调用bindService(),系统也只会在第一次绑定时调用onBind()和onServiceConnected方()法一次。这正是startService()与bindService()方法其中的区别,单从字面上理解startService()启动服务是可以多次执行,所以多次调用startService()方法都会触发onStartCommand()事件,而bindService()是绑定服务,所以只要服务已经被绑定,在未解绑时也不会多次执行onServiceConnected()绑定后的操作,这也是两者在使用场景上的区别所在。
Service生命周期图2.2
Service的运转流程就先介绍到这里,具体的使用方法将在下面的章节中详细介绍。
回到目录
三、LocalService应用原理与开发实例
3.1通过Context.startService启动Service服务
首先建立MyService继承Service,实现onCreate()、onDestory()、onStartCommand()、onStart()等几个方法,使用日志记录其运作信息。在Activity中通过Intent绑定Service服务,通过Context.startService()启动服务,通过Context.stopService()结束服务。
复制代码 1publicclassMainActivityextendsActivity{ 2 3@Override 4protectedvoidonCreate(BundlesavedInstanceState){ 5super.onCreate(savedInstanceState); 6setContentView(R.layout.activity_main); 7} 8 9publicvoidbtnStart_onclick(Viewview){ 10//通过Intent绑定MyService,加入输入参数 11Intentintent=newIntent(MainActivity.this,MyService.class); 12intent.putExtra("Name","Leslie"); 13Log.i(Context.ACTIVITY_SERVICE,"----------onClickstartService-----------"); 14//启动MyService 15startService(intent); 16} 17 18publicvoidbtnStop_onclick(Viewview){ 19Intentintent=newIntent(MainActivity.this,MyService.class); 20Log.i(Context.ACTIVITY_SERVICE,"----------onClickstopService------------"); 21//停止MyService 22stopService(intent); 23} 24} 25 26publicclassMyServiceextendsService{ 27 28@Override 29publicvoidonCreate(){ 30Log.i(Context.ACTIVITY_SERVICE,"ServiceonCreate"); 31super.onCreate(); 33} 34 35@Override 36publicvoidonDestroy(){ 37Log.i(Context.ACTIVITY_SERVICE,"ServiceonDestroy"); 38super.onDestroy(); 39} 40 41@Override 42publicvoidonStart(Intentintent,intstartId){ 43Log.i(Context.ACTIVITY_SERVICE,"ServiceonStart"); 44super.onStart(intent,startId); 45} 46 47@Override 48publicintonStartCommand(Intentintent,intflags,intstartId){ 49Log.i(Context.ACTIVITY_SERVICE,"ServiceonStartCommand"); 50Stringname=intent.www.wang027.comgetStringExtra("Name"); 51Log.i(Context.ACTIVITY_SERVICE,"Hisnameis"+name); 52returnsuper.onStartCommand(intent,flags,startId); 53} 54} 复制代码 AndroidManifest.xml文件绑定
复制代码 12android:name=".MainActivity" 3android:label="@string/title_activity_main"> 4 5 6 7 8 910android:name="android.services.MyService" 11android:enabled="true"> 12 复制代码 Service配置说明:
android:name服务类名,注意如果Service与Activity不在同一个包中,在android:name上必须写上Service的全路径 android:label服务的名字,如果为空,默认显示的服务名为类名 android:icon服务的图标 android:permission申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务 android:process表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字 android:enabled如果此项设置为true,那么Service将会默认被系统启动,默认值为false android:exported表示该服务是否能够被其他应用程序所控制或连接,默认值为false 查看处理结果可清楚看到,多次调用startService()后,使用stopService()结束Service服务,onCreate()、onDestory()只会在Service启动和结束时被调用一次。只有Service中的onStartCommand()方法会被多次调用。而Android2.0以下旧版的方法onStart()会在onStartCommand()调用过程中被激发。
3.2通过Context.bindService启动Service服务
在介绍Context.bindService()前,先讲解一下与此相关的常用类Binder、ServiceConnection,首先IBinder是Binder远程对象的基本接口,是为高性能而设计的轻量级远程调用机制的核心部分。这个接口定义了与远程对象交互的协议,但它不仅用于远程调用,也用于进程内调用。系统可以通过它以获取Service的句柄,在此先简单介绍它的基本用法,在下面关于RemoteService远程服务对象时再详细讲述IBinder的主体功能。ServiceConnection主要用于通过Binder绑定Service句柄后,对Service对象进行处理,它主要有两个方法voidonServiceConnected(ComponentNamename,IBinderservice)和voidonServiceDisconnected(ComponentNamename)。在Context.bindService()完成绑定后,系统就会调用onServiceConnected()方法,用户可以通过IBinder参数获取Service句柄,对Service进行处理。而onServiceDisconnected()方法一般不会被调用,只有Service被绑定后,由于内存不足等问题被意外kill时才会被调用。下面举个例子说明一下bindService()的用法。
复制代码 1publicclassMainActivityextendsActivity{ 2privateMyServiceConnectionserviceConnection; 3 4@Override 5protectedvoidonCreate(BundlesavedInstanceState){ 6super.onCreate(savedInstanceState); 7setContentView(R.layout.activity_main); 8 9serviceConnection=newMyServiceConnection(); 10} 11 12publicvoidbtnBind_onclick(Viewview){ 13//绑定MyService 14Intentintent=newIntent(this,MyService.class); 15 16Log.i(Context.ACTIVITY_SERVICE,"----------onClickbindService-----------"); 17//通过bindService(intent,serviceConnection,int)方式启动Service 18bindService(intent,this.serviceConnection,Context.BIND_AUTO_CREATE); 19} 20 21publicvoidbtnUnbind_onclick(Viewview){ 22Log.i(Context.ACTIVITY_SERVICE,"----------onClickunbindService----------"); 23unbindService(serviceConnection); 24} 25} 26 27publicclassMyServiceextendsService{ 28privateMyBindermyBinder; 29 30@Override 31publicIBinderonBind(Intentintent){ 32Log.i(Context.ACTIVITY_SERVICE,"ServiceonBind"); 33returnthis.myBinder; 34} 35 36@Override 37publicbooleanonUnbind(Intentintent){ 38Log.i(Context.ACTIVITY_SERVICE,"ServiceonUnbind"); 39returnsuper.onUnbind(intent); 40} 41 42@Override 43publicvoidonCreate(){ 44super.onCreate(); 45Log.i(Context.ACTIVITY_SERVICE,"ServiceonCreate"); 46myBinder=newMyBinder(); 47} 48 49@Override 50publicvoidonDestroy(){ 51Log.i(Context.ACTIVITY_SERVICE,"ServiceonDestroy"); 52super.onDestroy(); 53} 54 55publicStringgetDate(){ 56Calendarcalendar=Calendar.getInstance(); 57returncalendar.getTime().toString(); 58} 59 60publicclassMyBinderextendsBinder{ 61publicMyServicegetService(){ 62returnMyService.this; 63} 64} 65} 66 67publicclassMyServiceConnectionimplementsServiceConnection{ 68 69@Override 70publicvoidonServiceConnected(ComponentNamename,IBinderservice){ 71Log.i(Context.ACTIVITY_SERVICE,"ServiceConnected"); 72Stringdata=null; 73//通过IBinder获取Service句柄 74MyService.MyBindermyBinder=(MyService.MyBinder)service; 75MyServicemyService=myBinder.getService(); 76data=myService.getDate(); 77 78Log.i(Context.ACTIVITY_SERVICE,data); 79} 80 81@Override 82publicvoidonServiceDisconnected(ComponentNamename){ 83Log.i(Context.ACTIVITY_SERVICE,"ServiceDisconnected"); 84} 85} 复制代码 在运行时多次点击按钮激发btnBind_onclick(Viewview)方法后再使用btnUnbind_onclick(Viewview)结束服务,请留意处理结果。当系统调用Context.bindService()后,Service将跟随onCreate()、onBind()、onUnbind()、onDestory()的流程走下去。在成功完成onBind()绑定后,就会激发ServiceConnection对象的onServiceConnected()方法,在此用户可对Service进行处理。记得第2.2节所提过的问题,即使多次调用Context.bindService()方法,只要没有调用unbindService()结束绑定,系统只会在第一次调用时激发Service.onBind()和onServiceConnected()方法,这点从运行结果中可得到证实。
注意:调用Context.bindService()启动Service后,只能调用unbindService()一次,如重复多次调用此方法系统将会抛出错误异常。所以最简单的处理方式是设置一个静态变量booleanconnected,在调用unbindService()前先作出判断
复制代码 1publicclassMainActivityextendsActivity{ 2privateMyServiceConnectionserviceConnection; 3privatestaticbooleanconnected; 4 5@Override 6protectedvoidonCreate(BundlesavedInstanceState){ 7super.onCreate(savedInstanceState); 8setContentView(R.layout.activity_main); 9 10serviceConnection=newMyServiceConnection(); 11} 12 13publicvoidbtnBind_onclick(Viewview){ 14connected=true; 15//绑定MyService 16Intentintent=newIntent(this,MyService.class); 17 18Log.i(Context.ACTIVITY_SERVICE,"----------onClickbindService-----------"); 19//通过bindService(intent,serviceConnection,int)方式启动Service 20bindService(intent,this.serviceConnection,Context.BIND_AUTO_CREATE); 21} 22 23publicvoidbtnUnbind_onclick(Viewview){ 24Log.i(Context.ACTIVITY_SERVICE,"----------onClickunbindService----------"); 25if(connected){ 26unbindService(serviceConnection); 27connected=false; 28} 29} 30} 复制代码
3.3Service服务的综合运用
在前两节只是从初级阶段介绍了Service服务的使用原理,无论是使用startService()或者bindService()启动服务,Service服务的运行都是阶段性,当使用stopService()、unbindService()后,Service服务就会结束。然而从现实应用层面上看,Service服务很多时候是长驻后台的,它会记录程序运行的流程,当今的状态等重要信息。此时,更多的使用方式就是结合startService()、bindService()两种方式调用Service服务,startService()负责管理Service服务的启动,输入初始化参数,bindService()负责定时对Service服务进行检测。而且流程是有规律性,以startService()启动服务后,每使用bindService()绑定服务,就通过serviceConnection对服务进行检测,然后以unbindService()结束绑定。注意,此时服务并未结束,而是长期运行于后台,直到系统以stopService()方法结束服务后,Service才会最终完结。
复制代码 1publicclassMainActivityextendsActivity{ 2privateMyServiceConnectionserviceConnection; 3 4@Override 5protectedvoidonCreate(BundlesavedInstanceState){ 6super.onCreate(savedInstanceState); 7setContentView(R.layout.activity_main); 8 9serviceConnection=newMyServiceConnection(); 10} 11 12publicvoidbtnBind_onclick(Viewview){ 13//绑定MyService 14Intentintent=newIntent(this,MyService.class); 15 16Log.i(Context.ACTIVITY_SERVICE,"----------onClickbindService-----------"); 17//通过bindService(intent,serviceConnection,int)方式启动Service 18bindService(intent,this.serviceConnection,Context.BIND_AUTO_CREATE); 19} 20 21publicvoidbtnUnbind_onclick(Viewview){ 22Log.i(Context.ACTIVITY_SERVICE,"----------onClickunbindService----------"); 23unbindService(serviceConnection); 24} 25 26publicvoidbtnStart_onclick(Viewview){ 27//通过Intent绑定MyService,加入初始参数 28Intentintent=newIntent(MainActivity.this,MyService.class); 29intent.putExtra("param",0.88); 30Log.i(Context.ACTIVITY_SERVICE,"----------onClickstartService-----------"); 31//启动MyService 32startService(intent); 33} 34 35publicvoidbtnStop_onclick(Viewview){ 36Intentintent=newIntent(MainActivity.this,MyService.class); 37Log.i(Context.ACTIVITY_SERVICE,"----------onClickstopService------------"); 38//停止MyService 39stopService(intent); 40} 41} 42 43publicclassMyServiceextendsService{ 44privateMyBindermyBinder; 45privatedoubleparam; 46 47@Override 48publicvoidonStart(Intentintent,intstartId){ 49Log.i(Context.ACTIVITY_SERVICE,"ServiceonStart"); 50super.onStart(intent,startId); 51} 52 53@Override 54publicintonStartCommand(Intentintent,intflags,intstartId){ 55Log.i(Context.ACTIVITY_SERVICE,"ServiceonStartCommand"); 56//获取Context.startService设置的param初始值 57this.param=intent.getDoubleExtra("param",1.0); 58returnsuper.onStartCommand(intent,flags,startId); 59} 60 61@Override 62publicIBinderonBind(Intentintent){ 63Log.i(Context.ACTIVITY_SERVICE,"ServiceonBind"); 64returnthis.myBinder; 65} 66 67@Override 68publicbooleanonUnbind(Intentintent){ 69Log.i(Context.ACTIVITY_SERVICE,"ServiceonUnbind"); 70returnsuper.onUnbind(intent); 71} 72 73@Override 74publicvoidonCreate(){ 75super.onCreate(); 76Log.i(Context.ACTIVITY_SERVICE,"ServiceonCreate"); 77myBinder=newMyBinder(); 78} 79 80@Override 81publicvoidonDestroy(){ 82Log.i(Context.ACTIVITY_SERVICE,"ServiceonDestroy"); 83super.onDestroy(); 84} 85 86//获取处理后的值 87publicdoublegetValue(intvalue){ 88returnvalueparam; 89} 90 91publicclassMyBinderextendsBinder{ 92publicMyServicegetService(){ 93returnMyService.this; 94} 95} 96} 97 98publicclassMyServiceConnectionimplementsServiceConnection{ 99 100@Override 101publicvoidonServiceConnected(ComponentNamename,IBinderservice){ 102Log.i(Context.ACTIVITY_SERVICE,"ServiceConnected"); 103//通过IBinder获取Service句柄 104MyService.MyBindermyBinder=(MyService.MyBinder)service; 105MyServicemyService=myBinder.getService(); 106//生成随机数输入 107Randomrandom=newRandom(); 108doublevalue=myService.getValue(random.nextInt(10)1000); 109//显示计算结果 110Log.i(Context.ACTIVITY_SERVICE,String.valueOf(value)); 111} 112 113@Override 114publicvoidonServiceDisconnected(ComponentNamename){ 115Log.i(Context.ACTIVITY_SERVICE,"ServiceDisconnected"); 116} 117} 复制代码 通过startService()启动服务后,多次使用bindService()绑定服务,unbindService()解除绑定,最后通过stopService()结束服务后,可以看到下面的结果 这时候Service的onBind()方法和onUnbind()方法只在第一个bindService流程中触发,其后多次调用bindService(),此事件都不会被触发,而只会触发onServiceConnected()事件。这是因为在默认情况下,系统在绑定时会先搜索IBinder接口,如果Service已经绑定了Binder对象,系统就会直接跳过onBind()方法。
既然onBind(),onUnbind()方法只会在第一次启动绑定时被调用,如果在多次绑定时需要有不同的处理方式又该如何,还好Android为大家预备了一个备用方法voidonRebind(intent),Service服务中booleanonUnbind(intent)的默认返回值为false,只要将此方法的返回值修改为true,则系统在第二次调用Context.bindService()开始,就会激活Service.onRebind(intent)方法。在此对上面的方法作出少量修改,就会看到下面的处理结果。
复制代码 1publicclassMyServiceextendsService{ 2........... 3@Override 4publicvoidonRebind(Intentintent){ 5Log.i(Context.ACTIVITY_SERVICE,"ServiceonRebind"); 6super.onRebind(intent); 7} 8 9@Override 10publicbooleanonUnbind(Intentintent){ 11Log.i(Context.ACTIVITY_SERVICE,"ServiceonUnbind"); 12//将返回值设置为true 13returntrue; 14} 15........... 16........... 17} 复制代码 运行结果
注意:此使用方法只适用startService()、bindServcie()同时被调用的情况下,如果只调用其中一个方法,无论onUnbind()返回值为何值都无法触发onRebind()方法
回到目录
四、通过多线程方式处理Service的延时性操作
4.1以Runnable接口实现Service多线程操作
由于Android系统的资源有限,而且对屏幕显示,事件发应,用户体现都有较高的要求,所以在CPU、RAM、GPU、GPU都有独立的运行机制。当主线程中存在大文件读取、图片批量处理、网络连接超时等操作时,一旦时间超过5秒,Android系统就会出现“设置运行缓慢”的提示,Logcat日志上也会显示“Theapplicationmaybedoingtoomuchworkonitsmainthread”等提示。在开发Service服务时,若存在此类操作时,开发人员就应该尝试使用多线程方式进行开发,避免主线程被长时间占用。下文将以简单的Runnable接口方式实现多线程作为例子。
复制代码 1publicclassMainActivityextendsActivity{ 2 3@Override 4protectedvoidonCreate(BundlesavedInstanceState){ 5super.onCreate(savedInstanceState); 6setContentView(R.layout.activity_main); 7} 8 9publicvoidbtnStart_onclick(Viewview){ 10Intentintent=newIntent(MainActivity.this,MyService.class); 11Log.i(Context.ACTIVITY_SERVICE,"----------onClickstartService-----------------"); 12startService(intent); 13} 14 15publicvoidbtnStop_onclick(Viewview){ 16Intentintent=newIntent(MainActivity.this,MyService.class); 17Log.i(Context.ACTIVITY_SERVICE,"----------onClickstopService------------------"); 18stopService(intent); 19} 20} 21 22publicclassMyServiceextendsService{ 23 24@Override 25publicvoidonCreate(){ 26Log.i(Context.ACTIVITY_SERVICE,"ServiceonCreate"); 27super.onCreate(); 28} 29 30@Override 31publicintonStartCommand(Intentintent,intflags,intstartId){ 32Log.i(Context.ACTIVITY_SERVICE,"ServiceonStartCommand"); 33Log.i(Context.ACTIVITY_SERVICE,"Mainthreadidis"+Thread.currentThread().getId()); 34//以异步方式进行模拟操作 35Threadbackground=newThread(newAsyncRunnable()); 36background.start(); 37returnsuper.onStartCommand(intent,flags,startId); 38} 39 40@Override 41publicvoidonDestroy(){ 42Log.i(Context.ACTIVITY_SERVICE,"ServiceonDestroy"); 43super.onDestroy(); 44} 45} 46 47publicclassAsyncRunnableimplementsRunnable{ 48 49@Override 50publicvoidrun(){ 51try{ 52Log.i(Context.ACTIVITY_SERVICE,"Asyncthreadidis"+Thread.currentThread().getId()); 53//虚拟操作 54for(intn=0;n<8;n++){ 55Thread.sleep(1000); 56Log.i(Context.ACTIVITY_SERVICE,"DoWork"); 57} 58}catch(InterruptedExceptione){ 59//TODO自动生成的catch块 60e.printStackTrace(); 61} 62} 63} 复制代码 请留意运行结果,主线程与onStartCommand()方法内部操作存在于不同的线程当中完成
4.2IntentService服务简介
在Service服务中出现延时性操作是普遍遇到的情况,有见及此Android系统早为开发人员提供了一个Service的子类IntentService,当IntentService执行startService()方法时,系统将使用一个循环程序将该服务加入到一个子线程队列当中,以便执行服务当中的操作。下面为大家提供IntentService的源代码,让各位更好的理解IntentService的运行方式。
复制代码 1publicabstractclassIntentServiceextendsService{ 2privatevolatileLoopermServiceLooper; 3privatevolatileServiceHandlermServiceHandler; 4privateStringmName; 5privatebooleanmRedelivery; 6 7privatefinalclassServiceHandlerextendsHandler{ 8publicServiceHandler(Looperlooper){ 9super(looper); 10} 11 12@Override 13publicvoidhandleMessage(Messagemsg){ 14onHandleIntent((Intent)msg.obj); 15stopSelf(msg.arg1); 16} 17} 18 19publicIntentService(Stringname){ 20super(); 21mName=name; 22} 23 24publicvoidsetIntentRedelivery(booleanenabled){ 25mRedelivery=enabled; 26} 27 28@Override 29publicvoidonCreate(){ 30super.onCreate(); 31HandlerThreadthread=newHandlerThread("IntentService["+mName+"]"); 32thread.start(); 33 34mServiceLooper=thread.getLooper(); 35mServiceHandler=newServiceHandler(mServiceLooper); 36} 37 38@Override 39publicvoidonStart(Intentintent,intstartId){ 40Messagemsg=mServiceHandler.obtainMessage(); 41msg.arg1=startId; 42msg.obj=intent; 43mServiceHandler.sendMessage(msg); 44} 45 46@Override 47publicintonStartCommand(Intentintent,intflags,intstartId){ 48onStart(intent,startId); 49returnmRedelivery?START_REDELIVER_INTENT:START_NOT_STICKY; 50} 51 52@Override 53publicvoidonDestroy(){ 54mServiceLooper.quit(); 55} 56 57@Override 58publicIBinderonBind(Intentintent){ 59returnnull; 60} 61 62protectedabstractvoidonHandleIntent(Intentintent); 63} 复制代码 从代码中可以看到,系统没有在onStartCommand()中创建新线程,而是在onCreate()方法中建立了独立的工作线程,这是由于onCreate()方法只会在新建服务时被调用一次,可见这样的目的是为了让系统在单个线程中执行多个异步任务。当系统调用Context.startService()方法时,系统将通过onStart()方法使用异步方式,调用ServiceHandler.handleMessage(msg)进行处理,而handleMessage(msg)正是调用了虚拟方法onHandleIntent(intent),然后以stopSelf()结束服务。所以用户只需要在继承类中重写onHandleIntent(intent)方法,便可以以异步方法执行IntentService。
4.3IntentService应用
以下面一个简单的例子说明一下IntentService的应用,建立一个MyIntentService类继承IntentService,实现onHandleIntent(Messagemsg)方法。然后在MainActivity活动分别3次以不同参数调用intentService,观察其运行的线程状态。
复制代码 1publicclassMyIntentServiceextendsIntentService{ 2 3publicMyIntentService(){ 4super(null); 5} 6 7@Override 8protectedvoidonHandleIntent(Intentintent){ 9Stringmsg=intent.getStringExtra("msg"); 10Log.i(Context.ACTIVITY_SERVICE,msg+"''sthreadidis"+Thread.currentThread().getId()); 11} 12} 13 14publicclassMainActivityextendsActivity{ 15 16@Override 17protectedvoidonCreate(BundlesavedInstanceState){ 18super.onCreate(savedInstanceState); 19setContentView(R.layout.activity_main); 20} 21 22publicvoidbtnStart_onclick(Viewview){ 23Log.i(Context.ACTIVITY_SERVICE,"----------onClickstartService--------------"); 24Log.i(Context.ACTIVITY_SERVICE,"Mainthreadidis"+Thread.currentThread().getId()); 25 26Intentintent1=newIntent(this,MyIntentService.class); 27intent1.putExtra("msg","intentService1"); 28startService(intent1); 29 30Intentintent2=newIntent(this,MyIntentService.class); 31intent2.putExtra("msg","intentService2"); 32startService(intent2); 33 34Intentintent3=newIntent(this,MyIntentService.class); 35intent3.putExtra("msg","intentService3"); 36startService(intent3); 37} 38 39publicvoidbtnStop_onclick(Viewview){ 40Intentintent=newIntent(MainActivity.this,MyIntentService.class); 41Log.i(Context.ACTIVITY_SERVICE,"----------onClickstopService-------------"); 42stopService(intent); 43} 44} 复制代码 在AndroidManifest.xml文件设置服务
复制代码 1 2.......... 34android:name="android.services.MyIntentService" 5android:enabled="true"> 6 7 复制代码 从运行结果中可以看出,同一时间多次启动startService()调用intentService,它们都将运行于同一个异步线程当中,这一点在这里得到了证实。
回到目录
五、浅谈RemoteService原理
5.1跨进程通信的使用场景
以上章节所举的例子都是使用LocalService技术,Serivce服务端与Client客户端都是在于同一进程当中,当APP被卸御,Service服务也被同时卸御。要是想把服务端与客户端分别放在不同的进程当中进行跨进程信息交换的话,就需要使用到下面介绍的远程通信服务RemoteService。使用RemoteService可以把服务端与客户端分离,当一方被卸御,另一方不会被影响。当今有很多企业都有多个独立的APP,如阿里巴巴旗下就天猫、淘宝、聚划算、支付宝等多个APP,这时候就有需要把Service服务放在一独立的后台进程当中,作为多个APP之间信息交换的桥梁。这样如用户信息,用户登录,身份验证等多个共用的模块都可以在Service服务中实现,以供不同的APP进行调用。而且当APP被关闭时,Service服务还会寄存在后台当中,对用户的操作进行检测。如今越来越多的企业都使用这种开发方式,以收集用户像所在地点,通信录,短信,彩信等个人信息,方便企业针对用户的个人资料进行产品推广。
5.2RemoteService技术背景
Android系统与Windows系统的通信原则基本一致,进程就是安全策略的边界,不同的APP属于不同进程Process,一个进程不能直接访问其他进程的资源。需要实现多进程间的通信,就要使用IPC(InterProcessCommnication)进程间通信技术。Android系统的IPC机制是基于RPC(RemoteProceduceCall)远程过程调用协议建立的,与Java使用的RMI(RmoteMethedInvocation)远程方法调用相比,不同之处在于Android的IPC机制是基于AIDL(AndroidInterfaceDefinitionLanguage)接口定义语言定制进程间的通讯规则的。系统会基于AIDL规则把信息进行序列化处理,然后发送到另一个进程当中,Android系统把这种基于跨进程通信的服务称作RemoteService。
5.3IPC运作原理
从底层架构分析,Android系统中IPC的运作主要依赖于“ServiceManager”和“BinderDriver”两个核心元件,下面给大家简单介绍一下它们的运作原理:
ServiceManager简介 ServiceManager是Android系统内的服务管理器,主要负责管理Service服务的管理,注册,调用等任务。在Google提供的Android原始代码中可以找到(文件夹路径:frameworks/base/cmds/servicemanager),有C语言开发基础且有兴趣的朋友可以下载看一下,当中包含了几个核心的函数:
intsvcmgr_handler(structbinder_statebs,structbinder_txntxn,structbinder_iomsg,structbinder_ioreply) intdo_add_service(structbinder_statebs,uint16_ts,unsignedlen,voidptr,unsigneduid) voiddo_find_service(structbinder_statebs,uint16_ts,unsignedlen) voidbinder_loop(structbinder_statebs,binder_handlerfunc)
ServiceManager启动后会通过binder_loop循环对BinderDriver进行监听,当发现了有新的Service服务请求后,就会调用svcmgr_handler()函数对检测的Service服务进行处理,通过do_find_service()函数可以在svclist集中检测Service服务,若当前svclist服务集中未存在当前服务,就会通过do_add_service()进行注册,把当前服务及其唯一标识符加入到svclist中,这样当前的Service服务被绑定后就完成在ServiceManager的注册。BinderDriver会按照规定的格式把它转化为Binder实体发送到内核当中,当被Client调用时ServiceManager会根据Service服务的标识符在svclist中找到该Binder实体,并把Binder实体的引用发送给Client。完成计算后BinderDriver会进行数据处理,把计算结果发回到Client客户端。由于Binder实体是以强类型的形式存在,所以即使被多次引用,系统都会指向同一个Binder实体,除非所有都结束链接,否则Binder实体会一直存在。
图5.3
BinderDriver简介 BinderDriver运行于Android内核当中,它以“字符驱动设备”中的“misc设备注册”存在于设备目录dev/binder,由于权限问题,在一般手机中没有权限进行复制,对此有兴趣的朋友可以在google提供的android源代码中查看。它提供open(),mmap(),poll(),ioctl()等函数进行标准化文件操作,负责进程之间Binder通信的建立,Binder实体在进程之间的传递,Binder实体引用的计数管理,数据包在进程之间的传递与交互等一系列底层操作。
5.4RemoteService常用接口
在5.3节以Android底层结构的方式简单介绍了一下IPC通信的原理,下面将以JAVA应用层方式再作介绍。
IBinder接口 IBinder是RemoteService远程服务的常用接口,Binder是它的实现类,它是为高性能而设计的轻量级远程调用机制的核心部分。IBinder内部比较重要的方法就是booleantransact(intcode,Parceldata,Parcelreply,intflags),它负责在服务器与客户端之间进行信息交换,调用远程方法进行处理,然后把返回值转换成可序列化对象送回客户端。
5.5RemoteService开发实例
首先新建一个项目作为服务端,建立AIDL文件ITimerService.aidl,系统会根据接口描述自动在gen文件夹内生成对应的类文件ITimerService.java,当中Stub扩展了android.os.Binder并利用transact()实现了ITimerService接口中方法的远程调用。
1packagecom.example.remoteservice; 2 3interfaceITimerService{ 4StringgetTimeNow(); 5} gen\com\example\remoteservice\ITimerService.java(自动生成)
复制代码 1packagecom.example.remoteservice; 2publicinterfaceITimerServiceextendsandroid.os.IInterface 3{ 4/Local-sideIPCimplementationstubclass./ 5publicstaticabstractclassStubextendsandroid.os.Binderimplementscom.example.remoteservice.ITimerService 6{ 7privatestaticfinaljava.lang.StringDESCRIPTOR="com.example.remoteservice.ITimerService"; 8/Constructthestubatattachittotheinterface./ 9publicStub() 10{ 11this.attachInterface(this,DESCRIPTOR); 12} 13/ 14CastanIBinderobjectintoancom.example.remoteservice.ITimerServiceinterface, 15generatingaproxyifneeded. 16/ 17publicstaticcom.example.remoteservice.ITimerServiceasInterface(android.os.IBinderobj) 18{ 19if((obj==null)){ 20returnnull; 21} 22android.os.IInterfaceiin=obj.queryLocalInterface(DESCRIPTOR); 23if(((iin!=null)&&(iininstanceofcom.example.remoteservice.ITimerService))){ 24return((com.example.remoteservice.ITimerService)iin); 25} 26returnnewcom.example.remoteservice.ITimerService.Stub.Proxy(obj); 27} 28@Overridepublicandroid.os.IBinderasBinder() 29{ 30returnthis; 31} 32@OverridepublicbooleanonTransact(intcode,android.os.Parceldata,android.os.Parcelreply,intflags)throwsandroid.os.RemoteException 33{ 34switch(code) 35{ 36caseINTERFACE_TRANSACTION: 37{ 38reply.writeString(DESCRIPTOR); 39returntrue; 40} 41caseTRANSACTION_getTimeNow: 42{ 43data.enforceInterface(DESCRIPTOR); 44java.lang.String_result=this.getTimeNow(); 45reply.writeNoException(); 46reply.writeString(_result); 47returntrue; 48} 49} 50returnsuper.onTransact(code,data,reply,flags); 51} 52privatestaticclassProxyimplementscom.example.remoteservice.ITimerService 53{ 54privateandroid.os.IBindermRemote; 55Proxy(android.os.IBinderremote) 56{ 57mRemote=remote; 58} 59@Overridepublicandroid.os.IBinderasBinder() 60{ 61returnmRemote; 62} 63publicjava.lang.StringgetInterfaceDescriptor() 64{ 65returnDESCRIPTOR; 66} 67@Overridepublicjava.lang.StringgetTimeNow()throwsandroid.os.RemoteException 68{ 69android.os.Parcel_data=android.os.Parcel.obtain(); 70android.os.Parcel_reply=android.os.Parcel.obtain(); 71java.lang.String_result; 72try{ 73_data.writeInterfaceToken(DESCRIPTOR); 74mRemote.transact(Stub.TRANSACTION_getTimeNow,_data,_reply,0); 75_reply.readException(); 76_result=_reply.readString(); 77} 78finally{ 79_reply.recycle(); 80_data.recycle(); 81} 82return_result; 83} 84} 85staticfinalintTRANSACTION_getTimeNow=(android.os.IBinder.FIRST_CALL_TRANSACTION+0); 86} 87publicjava.lang.StringgetTimeNow()throwsandroid.os.RemoteException; 88} 复制代码 然后建立服务TimerService,建立内置类TimerServiceImpl实现接口ITimerService中的方法,由于使用RemoteService只能使用bindService()方式对服务进行远程绑定,所以TimerService中须利用onBind()方法绑定TimerServiceImpl对象。
复制代码 1publicclassTimerServiceextendsService{ 2 3@Override 4publicIBinderonBind(Intentintent){ 5//TODO自动生成的方法存根 6returnnewTimerServiceImpl(); 7} 8 9publicclassTimerServiceImplextendsITimerService.Stub{ 10 11@Override 12publicStringgetTimeNow()throwsRemoteException{ 13//获取当时时间与服务器端的进程Id 14Datedate=newDate(); 15SimpleDateFormatformatter=newSimpleDateFormat("Eyyyy.MM.dd''at''hh:mm:ssazzz"); 16return"Timenowis"+formatter.format(date)+"\nServiceprocessIdis"+Process.myPid(); 17} 18} 19} 复制代码 在AndroidManifest.xml文件设置服务绑定,在action项的android:name中绑定当前服务的接口
复制代码 1 2........ 3 4 5 6 7 8 复制代码 服务器端完成配置后建立一个客户端项目,把ITimerService.aidl文件copy到客户端,此时客户端也会在gen文件夹中自动生成ITimerService.java文件。在Activity中调用RemoteService时请注意,android4.0及以下版本,可通过Intent(stringaction)构造函数生成后直接调用。android5.0及以上版本需通过intent.setPackage(stringpackageName)指定action的包名称。
复制代码 1publicclassMainActivityextendsActivity{ 2privateMyServiceConnectionserviceConnection; 3privatebooleanconnected; 4 5@Override 6protectedvoidonCreate(BundlesavedInstanceState){ 7super.onCreate(savedInstanceState); 8setContentView(R.layout.activity_main); 9//建立ServiceConnection对象 10serviceConnection=newMyServiceConnection(); 11} 12 13publicvoidbtnBind_onclick(Viewview){ 14Intentintent=newIntent(); 15//绑定远程服务接口 16intent.setAction("com.example.remoteservice.ITimerService"); 17intent.setPackage("com.example.remoteservice"); 18this.connected=true; 19Log.i(Context.ACTIVITY_SERVICE,"-------onClickbindService--------"); 20bindService(intent,this.serviceConnection,Context.BIND_AUTO_CREATE); 21} 22 23publicvoidbtnUnbind_onclick(Viewview){ 24Log.i(Context.ACTIVITY_SERVICE,"-------onClickunbindService---------"); 25if(connected){ 26unbindService(serviceConnection); 27connected=false; 28} 29} 30} 31 32publicclassMyServiceConnectionimplementsServiceConnection{ 33 34@Override 35publicvoidonServiceConnected(ComponentNamename,IBinderservice){ 36//TODO自动生成的方法存根 37Log.i(Context.ACTIVITY_SERVICE,"ServiceConnected"); 38//获取远程对象 39ITimerServicetimerService=ITimerService.Stub.asInterface(service); 40Stringdata=null; 41 42try{ 43data=timerService.getTimeNow()+"\nClientprocessIdis"+Process.myPid(); 44}catch(RemoteExceptione){ 45//TODO自动生成的catch块 46e.printStackTrace(); 47} 48 49Log.i(Context.ACTIVITY_SERVICE,data); 50} 51} 复制代码 从运行结果可清晰看到Service与Client运行于不同的进程当中
5.6RemoteService复杂类型数据传输
当RemoteService需要使用自定义类型的数据进行传输时,数据对象需要经过序列化处理,而Android对象的序列化处理有两种方式,一是常用方式Serializable接口,另一个是Android独有的Parcelable接口。由于常用的Serializable接口,会使用大量的临时变量耗费内存而导致大量的GC垃圾回收,引起手机资源不足,因此Android研发出Parcelable接口实现对象的序列化。它可被看作为一个Parcel容器,通过writeToParcel()与createFormParcel()方法把对象读写到Parcel当中,Parcelable接口如下:
复制代码 1publicinterfaceParcelable 2{ 3//内容描述接口 4publicintdescribeContents(); 5//对象序列化方式 6publicvoidwriteToParcel(Parceldest,intflags); 7 8//反序列化对象,使用泛型方式在Parcel中构造一个实现了Parcelable的类的实例处理。 9//接口分别定义了单个实例和多个实例 10publicinterfaceCreator 11{ 12publicTcreateFromParcel(Parcelsource); 13publicT[]newArray(intsize); 14} 15} 复制代码 首先建立服务端,新建Person.aidl文件
1packagecom.example.remoteservice; 2 3parcelablePerson; 建立Person类,实现Parcelable接口
复制代码 1publicclassPersonimplementsParcelable{ 2privateStringname; 3privateIntegerage; 4privateStringdesc; 5 6publicPerson(){ 7 8} 9 10publicPerson(Stringname,Integerage,Stringdesc){ 11//TODO自动生成的构造函数存根 12this.name=name; 13this.age=age; 14this.desc=desc; 15} 16 17publicStringgetName(){ 18returnthis.name; 19} 20 21publicvoidsetName(Stringname){ 22this.name=name; 23} 24 25publicIntegergetAge(){ 26returnthis.age; 27} 28 29publicvoidsetAge(Integerage){ 30this.age=age; 31} 32 33publicStringgetDesc(){ 34returnthis.desc; 35} 36 37publicvoidsetDesc(Stringdesc){ 38this.desc=desc; 39} 40 41@Override 42publicintdescribeContents(){ 43//TODO自动生成的方法存根 44return0; 45} 46 47@Override 48publicvoidwriteToParcel(Parceldest,intflags){ 49//TODO自动生成的方法存根 50dest.writeString(name); 51dest.writeInt(age); 52dest.writeString(desc); 53} 54 55publicstaticfinalParcelable.CreatorCREATOR=newCreator(){ 56 57/ 58创建一个要序列号的实体类的数组,数组中存储的都设置为null 59/ 60@Override 61publicPerson[]newArray(intsize){ 62returnnewPerson[size]; 63} 64 65/ 66根据序列号的Parcel对象,反序列号为原本的实体对象 67读出顺序要和writeToParcel的写入顺序相同 68/ 69@Override 70publicPersoncreateFromParcel(Parcelsource){ 71Stringname=source.readString(); 72intage=source.readInt(); 73Stringdesc=source.readString(); 74PersonPerson=newPerson(); 75Person.setName(name); 76Person.setAge(age); 77Person.setDesc(desc); 78 79returnPerson; 80} 81}; 82} 复制代码 建立服务IPersonService.aidl文件
复制代码 1packagecom.example.remoteservice; 2 3importcom.example.remoteservice.Person; 4 5interfaceIPersonService{ 6PersongetPerson(Stringnumber); 7} 复制代码 此时在gen\com\example\remoteservice文件夹内将自动生成成IPersonService.java类
复制代码 1/ 2Thisfileisauto-generated.DONOTMODIFY. 3Originalfile:D:\\Java_Projects\\RemoteService\\src\\com\\example\\remoteservice\\IPersonService.aidl 4/ 5packagecom.example.remoteservice; 6publicinterfaceIPersonServiceextendsandroid.os.IInterface 7{ 8/Local-sideIPCimplementationstubclass./ 9publicstaticabstractclassStubextendsandroid.os.Binderimplementscom.example.remoteservice.IPersonService 10{ 11privatestaticfinaljava.lang.StringDESCRIPTOR="com.example.remoteservice.IPersonService"; 12/Constructthestubatattachittotheinterface./ 13publicStub() 14{ 15this.attachInterface(this,DESCRIPTOR); 16} 17/ 18CastanIBinderobjectintoancom.example.remoteservice.IPersonServiceinterface, 19generatingaproxyifneeded. 20/ 21publicstaticcom.example.remoteservice.IPersonServiceasInterface(android.os.IBinderobj) 22{ 23if((obj==null)){ 24returnnull; 25} 26android.os.IInterfaceiin=obj.queryLocalInterface(DESCRIPTOR); 27if(((iin!=null)&&(iininstanceofcom.example.remoteservice.IPersonService))){ 28return((com.example.remoteservice.IPersonService)iin); 29} 30returnnewcom.example.remoteservice.IPersonService.Stub.Proxy(obj); 31} 32@Overridepublicandroid.os.IBinderasBinder() 33{ 34returnthis; 35} 36@OverridepublicbooleanonTransact(intcode,android.os.Parceldata,android.os.Parcelreply,intflags)throwsandroid.os.RemoteException 37{ 38switch(code) 39{ 40caseINTERFACE_TRANSACTION: 41{ 42reply.writeString(DESCRIPTOR); 43returntrue; 44} 45caseTRANSACTION_getPerson: 46{ 47data.enforceInterface(DESCRIPTOR); 48java.lang.String_arg0; 49_arg0=data.readString(); 50com.example.remoteservice.Person_result=this.getPerson(_arg0); 51reply.writeNoException(); 52if((_result!=null)){ 53reply.writeInt(1); 54_result.writeToParcel(reply,android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 55} 56else{ 57reply.writeInt(0); 58} 59returntrue; 60} 61} 62returnsuper.onTransact(code,data,reply,flags); 63} 64privatestaticclassProxyimplementscom.example.remoteservice.IPersonService 65{ 66privateandroid.os.IBindermRemote; 67Proxy(android.os.IBinderremote) 68{ 69mRemote=remote; 70} 71@Overridepublicandroid.os.IBinderasBinder() 72{ 73returnmRemote; 74} 75publicjava.lang.StringgetInterfaceDescriptor() 76{ 77returnDESCRIPTOR; 78} 79@Overridepubliccom.example.remoteservice.PersongetPerson(java.lang.Stringnumber)throwsandroid.os.RemoteException 80{ 81android.os.Parcel_data=android.os.Parcel.obtain(); 82android.os.Parcel_reply=android.os.Parcel.obtain(); 83com.example.remoteservice.Person_result; 84try{ 85_data.writeInterfaceToken(DESCRIPTOR); 86_data.writeString(number); 87mRemote.transact(Stub.TRANSACTION_getPerson,_data,_reply,0); 88_reply.readException(); 89if((0!=_reply.readInt())){ 90_result=com.example.remoteservice.Person.CREATOR.createFromParcel(_reply); 91} 92else{ 93_result=null; 94} 95} 96finally{ 97_reply.recycle(); 98_data.recycle(); 99} 100return_result; 101} 102} 103staticfinalintTRANSACTION_getPerson=(android.os.IBinder.FIRST_CALL_TRANSACTION+0); 104} 105publiccom.example.remoteservice.PersongetPerson(java.lang.Stringnumber)throwsandroid.os.RemoteException; 106} 复制代码 然后建立服务PersonService,建立内置类PersonServiceImpl实现接口IPersonService中的方法,在PersonService中须利用onBind()方法绑定PersonServiceImpl对象。
复制代码 1publicclassPersonServiceextendsService{ 2 3@Override 4publicIBinderonBind(Intentintent){ 5//TODO自动生成的方法存根 6returnnewPersonServiceImpl(); 7} 8 9publicclassPersonServiceImplextendsIPersonService.Stub{ 10@Override 11publicPersongetPerson(Stringnumber)throwsRemoteException{ 12//TODO自动生成的方法存根 13switch(number){ 14case"0": 15returnnewPerson("JackMokei",34,"ProjectManager"); 16case"1": 17returnnewPerson("MikeTlea",24,"TeamLeader"); 18default: 19returnnull; 20} 21} 22} 23} 复制代码 在AndroidManifest.xml文件设置服务绑定,在action项的android:name中绑定当前服务的接口
复制代码 1 2........ 3 4 5 6 7 8 复制代码 服务器端完成配置后建立一个客户端项目,把Person.aidl、IPersonService.aidl文件copy到客户端,此时客户端也会在gen文件夹中自动生成Person.java和IPersonService.java文件
复制代码 1publicclassMainActivityextendsActivity{ 2privateMyServiceConnectionserviceConnection; 3privatebooleanconnected; 4 5@Override 6protectedvoidonCreate(BundlesavedInstanceState){ 7super.onCreate(savedInstanceState); 8setContentView(R.layout.activity_main); 9//建立ServiceConnection对象 10serviceConnection=newMyServiceConnection(); 11} 12 13publicvoidbtnBind_onclick(Viewview){ 14Intentintent=newIntent(); 15//绑定远程服务接口 16intent.setAction("com.example.remoteservice.IPersonService"); 17intent.setPackage("com.example.remoteservice"); 18this.connected=true; 19Log.i(Context.ACTIVITY_SERVICE,"----------onClickbindService----------"); 20bindService(intent,this.serviceConnection,Context.BIND_AUTO_CREATE); 21} 22 23publicvoidbtnUnbind_onclick(Viewview){ 24Log.i(Context.ACTIVITY_SERVICE,"----------onClickunbindService--------"); 25if(connected){ 26unbindService(serviceConnection); 27connected=false; 28} 29} 30} 31 32publicclassMyServiceConnectionimplementsServiceConnection{ 33 34@Override 35publicvoidonServiceConnected(ComponentNamename,IBinderservice){ 36Log.i(Context.ACTIVITY_SERVICE,"ServiceConnected"); 37//绑定远程对象 38IPersonServicepersonService=IPersonService.Stub.asInterface(service); 39Stringdata=null; 40 41try{ 42Personperson=personService.getPerson("0"); 43data=person.getName()+"''sageis"+person.getAge(); 44}catch(RemoteExceptione){ 45//TODO自动生成的catch块 46e.printStackTrace(); 47} 48 49Log.i(Context.ACTIVITY_SERVICE,data); 50} 51} |
|