Service Activity的三种交互方式(详解)
service有两种类型:
本地服务(LocalService):用于应用程序内部
远程服务(RemoteSercie):用于android系统内部的应用程序之间
前者用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。
后者可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
编写不需和Activity交互的本地服务示例
本地服务编写比较简单。首先,要创建一个Service类,该类继承android的Service类。这里写了一个计数服务的类,每秒钟为计数器加一。在服务类的内部,还创建了一个线程,用于实现后台执行上述业务逻辑。
Service代码:
importandroid.app.Service; importandroid.content.Intent; importandroid.os.IBinder; importandroid.util.Log; publicclassCountServiceextendsService{ privatebooleanthreadDisable; privateintcount; @Override publicIBinderonBind(Intentintent){ returnnull; } @Override publicvoidonCreate(){ super.onCreate(); newThread(newRunnable(){ publicvoidrun(){ while(!threadDisable){ try{ Thread.sleep(1000); }catch(InterruptedExceptione){ } count++; System.out.println("CountServiceCountis"+count); } } }).start(); } @Override publicvoidonDestroy(){ super.onDestroy(); this.threadDisable=true; Log.v("CountService","ondestroy"); } } 将该服务注册到配置文件AndroidManifest.xml中 <serviceandroid:name="CountService"/> 在Activity中启动和关闭本地服务 importandroid.app.Activity; importandroid.content.Intent; importandroid.os.Bundle; publicclassLocalServiceDemoActivityextendsActivity{ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); this.startService(newIntent(this,CountService.class)); } @Override protectedvoidonDestroy(){ super.onDestroy(); this.stopService(newIntent(this,CountService.class)); } }
编写本地服务和Activity交互的示例
上面的示例是通过startService和stopService启动关闭服务的。适用于服务和activity之间没有调用交互的情况。如果之间需要传递参数或者方法调用。需要使用bind和unbind方法。
具体做法是,服务类需要增加接口,比如ICountService,另外,服务类需要有一个内部类,这样可以方便访问外部类的封装数据,这个内部类需要继承Binder类并实现ICountService接口。还有,就是要实现Service的
onBind方法,不能只传回一个null了。
新建立的接口代码:
publicinterfaceICountService{ publicabstractintgetCount(); } CountService代码: importandroid.app.Service; importandroid.content.Intent; importandroid.os.Binder; importandroid.os.IBinder; importandroid.util.Log; publicclassCountServiceextendsServiceimplementsICountService{ privatebooleanthreadDisable; privateintcount; privateServiceBinderserviceBinder=newServiceBinder(); publicclassServiceBinderextendsBinderimplementsICountService{ //@Override publicintgetCount(){ returncount; } } @Override publicIBinderonBind(Intentintent){ returnserviceBinder; } @Override publicvoidonCreate(){ super.onCreate(); newThread(newRunnable(){ //@Override publicvoidrun(){ while(!threadDisable){ try{ Thread.sleep(1000); }catch(InterruptedExceptione){ } count++; System.out.println("CountServiceCountis"+count); } } }).start(); } @Override publicvoidonDestroy(){ super.onDestroy(); this.threadDisable=true; Log.v("CountService","ondestroy"); } //@Override publicintgetCount(){ returncount; } }
服务的注册也要做改动,AndroidManifest.xml文件:
<serviceandroid:name="CountService"> <intent-filter> <actionandroid:name="com.phone.jiaohuservice.CountService"/> </intent-filter> </service> Acitity代码不再通过startSerivce和stopService启动关闭服务,另外,需要通过ServiceConnection的内部类实现来连接Service和Activity。 importandroid.app.Activity; importandroid.content.ComponentName; importandroid.content.Intent; importandroid.content.ServiceConnection; importandroid.os.Bundle; importandroid.os.IBinder; publicclassLocalServiceDemoActivityextendsActivity{ privateServiceConnectionserviceConnection=newServiceConnection(){ //@Override publicvoidonServiceConnected(ComponentNamename,IBinderservice){ countService=(ICountService)service; System.out.println("CountServiceonserivceconnected,countis" +countService.getCount()); } //@Override publicvoidonServiceDisconnected(ComponentNamename){ countService=null; } }; privateICountServicecountService; /**Calledwhentheactivityisfirstcreated.*/ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); this.bindService(newIntent("com.phone.jiaohuservice.CountService"), this.serviceConnection,BIND_AUTO_CREATE); } @Override protectedvoidonDestroy(){ this.unbindService(serviceConnection); super.onDestroy();//注意先后 } }
编写传递基本型数据的远程服务
上面的示例,可以扩展为,让其他应用程序复用该服务。这样的服务叫远程(remote)服务,实际上是进程间通信(RPC)。
这时需要使用android接口描述语言(AIDL)来定义远程服务的接口,而不是上述那样简单的java接口。扩展名为aidl而不是java。可用上面的ICountService改动而成ICountSerivde.aidl,eclipse会自动生成相关的java文件。
远端代码:
ICountService.aidl
packagecom.phone.remoteservice.aidl; interfaceICountService{ intgetCount(); }
CountService.java
importcom.phone.remoteservice.aidl.ICountService; importandroid.app.Service; importandroid.content.Intent; importandroid.os.IBinder; importandroid.os.RemoteException; importandroid.util.Log; publicclassCountServiceextendsService{ privatebooleanthreadDisable; privateintcount; privateICountService.StubserviceBinder=newICountService.Stub(){ //@Override publicintgetCount()throwsRemoteException{ returncount; } }; //@Override publicIBinderonBind(Intentintent){ returnserviceBinder; } @Override publicvoidonCreate(){ super.onCreate(); newThread(newRunnable(){ //@Override publicvoidrun(){ while(!threadDisable){ try{ Thread.sleep(1000); }catch(InterruptedExceptione){ } count++; Log.i("aa","---"+count+"---"); } } }).start(); } //@Override publicvoidonDestroy(){ super.onDestroy(); this.threadDisable=true; Log.v("CountService","ondestroy"); } }
配置文件AndroidManifest.xml
<serviceandroid:name=".CountService"> <intent-filter> <actionandroid:name="com.phone.remoteservice.CountService"/> </intent-filter> </service>
本地代码:
拷贝远端代码gen:com.phone.remoteservice.aidl包名及内部生成的ICountService.java文件到本地,注意包名不要变,java文件名也不要变。
测试代码
importcom.phone.remoteservice.aidl.ICountService; importandroid.os.Bundle; importandroid.os.IBinder; importandroid.os.RemoteException; importandroid.app.Activity; importandroid.content.ComponentName; importandroid.content.Intent; importandroid.content.ServiceConnection; importandroid.view.Menu; publicclassRemoteServiceTestextendsActivity{ privateICountServicecountService; privatebooleanSreviceDisable; /**Calledwhentheactivityisfirstcreated.*/ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); bindService(newIntent("com.phone.remoteservice.CountService"), this.serviceConnection,BIND_AUTO_CREATE); } @Override protectedvoidonDestroy(){ this.unbindService(serviceConnection); SreviceDisable=true; super.onDestroy();//注意先后 } privateServiceConnectionserviceConnection=newServiceConnection(){ publicvoidonServiceConnected(ComponentNamename,IBinderservice){ countService=ICountService.Stub.asInterface(service); newThread(newRunnable(){ //@Override publicvoidrun(){ while(!SreviceDisable){ try{ System.out .println("CountServiceonserivceconnected,countis" +countService.getCount()); }catch(RemoteExceptione){ e.printStackTrace(); } try{ Thread.sleep(1000); }catch(InterruptedExceptione){ } } } }).start(); } publicvoidonServiceDisconnected(ComponentNamename){ countService=null; } }; }
在Activity中使用服务的差别不大,只需要对ServiceConnection中的调用远程服务的方法时,要捕获RemoteException异常。
这样就可以在同一个应用程序中使用远程服务的方式和自己定义的服务交互了。如果是另外的应用程序使用远程服务,需要做的是复制上面的aidl文件和相应的包构到应用程序中,其他调用等都一样。
编写传递复杂数据类型的远程服务
远程服务往往不只是传递java基本数据类型。这时需要注意android的一些限制和规定:
1.android支持String和CharSequence
2.如果需要在aidl中使用其他aidl接口类型,需要import,即使是在相同包结构下;
3.android允许传递实现Parcelable接口的类,需要import;
4.android支持集合接口类型List和Map,但是有一些限制,元素必须是基本型或者上述三种情况,不需要import集合接口类,但是需要对元素涉及到的类型import;
5.非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。
这里将前面的例子中返回的int数据改为复杂数据类型:
importandroid.os.Parcel; importandroid.os.Parcelable; publicclassCountBeanimplementsParcelable{ publicstaticfinalParcelable.Creator<CountBean>CREATOR=newCreator<CountBean>(){ @Override publicCountBeancreateFromParcel(Parcelsource){ CountBeanbean=newCountBean(); bean.count=source.readInt(); returnbean; } @Override publicCountBean[]newArray(intsize){ returnnewCountBean[size]; } }; publicintcount; @Override publicvoidwriteToParcel(Parceldest,intflags){ dest.writeInt(this.count); } @Override publicintdescribeContents(){ return0; } }
以上就是小编为大家带来的ServiceActivity的三种交互方式(详解)的全部内容了,希望对大家有所帮助,多多支持毛票票~