Service与AIDL讲解
来源:互联网 发布:通于心术 知类在穷 编辑:程序博客网 时间:2024/05/16 14:46
转自:http://johnsonxu.iteye.com/blog/1182436
一个Service,从本质上来说,可以有两种形式。
1、 通过startService()启动。这种情况下,该Service与启动它的组件是完全独立的,即使组件被销毁,Service仍会继续,不会自动结束,而且通常情况下不返回任何结果。因此,应在Service执行完毕后调用stopSelf(int)(最好用带参数的,防止一个Service被多个组件请求的情况下,把还在执行的请求结束了)或其他组件调用stopService关闭Service。
2、 通过bindService()启动。其生命周期与绑定该Service的组件有关,可以多个组件绑定一个Service,但当所有组件都解绑后,该Service将被销毁。但是当有组件绑定一个Service时,该Service无法以stopService或stopSelf的方式终止。
默认情况下,任何组件都可以访问Service,但是我们可以在AndroidManifest.xml中将其声明为私有的,从而拒绝其他应用中的组件访问本应用的Service。通过设置intent-filter,可以使得Service能够被隐式调用。
同时,一个Service默认情况下运行在它的宿主进程的主线程(除非在AndroidManifest.xml中另行设置),因此,若要在一个Service中执行一些复杂的操作,最好在Service的执行代码中新建一个线程,在里面运行。这样能够降低系统出现Application Not Responding (ANR)错误的风险。
若只想在Activity运行时在后台执行某些操作,可以在Activity的onCreate中新建一个线程,在onStart中启动,在onStop中停止。而不是采用Service的方式。
创建过程:继承Service类,实现生命周期方法。与Activity不同,Service不需要调用父类方法。
1、 onStartCommand:当该Service被其他组件以startService的方式调用后,执行该方法。不同的返回值可以设置当系统内存不足时,对该Service的处理方式。START_NOT_STICKY:销毁后不自动创建。START_STICKY:销毁后重新创建Service,并执行onStartCommand,但传入的intent是空的。START_REDELIVER_INTENT:在START_STICKY基础上,传入了最后传入的那个intent。
2、 onBind:当该Service被其他组件以bindService的方式调用后,执行该方法。绑定后,该Service的生命周期就与绑定它的组件相关联。这种情况下,不用在代码里停止Service。要支持Service绑定,需要返回一个IBinder接口的实例(使用内部类继承Binder类定义并创建,Binder类实现了IBinder接口),在里面定义一些自己需要的方法,以便Service的绑定者与该Service之间的交互。
- class MyBinder extends Binder{
- // 比如说,定义一个停止Service的方法
- public void stopService(){
- MyService.this.stopSelf();
- }
- // 甚至可以定义一个返回该Service对象的方法
- public MyService getService(){
- return MyService.this;
- }
- }
- @Override
- public IBinder onBind(Intent arg0) {
- Log.d(TAG, "onBind");
- return new MyBinder();
- }
然后就可以在Service的绑定者(比如说Activity)的代码里对其进行操作
- MyService myService;
- MyService.MyBinder localBinder;
- // 定义ServiceConnection对象并在Service连接时获取相关对象
- private ServiceConnection mConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName className,IBinder binder)
- {
- localBinder = (MyService.MyBinder) binder;
- myService = localBinder.getService();
- }
- @Override
- public void onServiceDisconnected(ComponentName arg0) {
- }
- };
- // 然后进行绑定
- Intent intent2=new Intent();
- intent2.setClass(context, MyService.class);
- context.bindService(intent2, mConnection, Context.BIND_AUTO_CREATE);
3、 onCreate:只在Service第一次被创建时调用,其调用在onStartCommand与onBind之前。
4、 onDestroy:销毁时调用。
对于onStartCommand和onBind,可以只实现其中一种。
不能从BroadcastReceiver中调用bindService。但如果是用registerReceiver的方式注册过的BroadcastReceiver,由于其生命周期与Activity绑定,则可以。
IntentService是Service的子类,其中采用了一个工作者线程来处理所有的Intent请求(串行);当请求执行完毕后自动调用stopSelf方法;提供返回null的onBind的实现;提供onStartCommand的默认实现,并把请求转发至onHandleIntent方法(需自行实现)。若不需要所有请求同时处理,建议通过继承该类来实现Service。
前台Service:可以在通知栏中看到的Service。
当一个Service处于前台模式下时,系统不会在内存不足时销毁它。同时,前台Service需要在通知栏上显示一个图标及相应信息。并支持从通知栏启动相应的Activity。可以在Service的onStartCommand方法中根据传入的intent中的内容的不同,修改状态。
- // service内执行
- // 此处的title是一个通知生成时,在通知栏显示的提示消息
- Notification notification = new Notification(R.drawable.icon, "title",System.currentTimeMillis());
- // 为了能在通知栏拉下来后,点击通知能够打开Activity,使用了PendingIntent
- Intent notificationIntent = new Intent(this, BroadcastActivity.class);
- PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
- // 此处的title2是把通知栏拉下来后,显示的标题。content即文本内容。
- notification.setLatestEventInfo(this, "title2","content", pendingIntent);
- // 设置为前台显示
- startForeground(id, notification);
不想在前台显示时,在Service中执行stopForeground(true);即可。
只有Activity,Service,ContentProvider能够绑定Service,BroadcastReceiver不可以。
如果想要在每次绑定时都执行一遍onBind,要在onUnbind中返回true。否则,当下一次有组件绑定该服务时,将运行onRebind,而不是onBind。如下图:
进程间通信
当要在Service中支持IPC(进程间通信)时,可以使用Messenger(不需要多线程)或AIDL(需要支持多线程访问服务)。
Messenger:
1、 在Service中实现一个Handler,在它的handleMessage方法中处理包含不同Message的请求。
2、 在Service中创建Messenger对象(公共,参数是自定义Handler对象),在onBind时,使用Messenger的getBinder方法返回绑定的IBinder对象。
3、 调用时,在ServiceConnection类的onServiceConnected方法中,利用IBinder对象创建Messenger对象。然后在想要调用服务的地方使用它的send方法发送Message对象给Service。
AIDL
注:对AIDL的访问相当于函数调用,无法保证其运行在哪个线程。
对AIDL的调用是同步调用,调用完毕函数才返回。如果是比较耗时的工作,注意不要在主线程中调用,防止界面卡死(ANR)。
实现过程:
1、 定义AIDL文件,定义完后,Eclipse会自动在gen的相应目录生成一个.java文件。
- interface MyAidl {
- int getPid();
- void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,double aDouble, String aString);
- void stopService();
- }
2、 在自己实现的Service中,创建一个Stub类(Binder的子类,在.java中自动生成的)对象,给出相应方法的实现。
- public class AidlBinder extends MyAidl.Stub{
- @Override
- public void basicTypes(int anInt, long aLong, boolean
- aBoolean,float aFloat, double aDouble, String aString)
- throws RemoteException
- {
- Log.d(TAG, "basicTypes");
- }
- @Override
- public int getPid() throws RemoteException {
- Log.d(TAG, "getPid");
- return 0;
- }
- @Override
- public void stopService() throws RemoteException {
- MyService.this.stopSelf();
- }
- }
3、 将Stub对象通过onBind传给调用者
- @Override
- public IBinder onBind(Intent arg0) {
- return myAidlBinder;
- }
4、 在调用者的代码中,利用asInterface方法获取接口对象(若处于不同应用,调用者应能获取aidl文件,以便自动生成接口类)。
- MyAidl aidl;
- private ServiceConnection mConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName
- className,IBinder binder) {
- aidl=MyAidl.Stub.asInterface(binder);
- }
- @Override
- public void onServiceDisconnected(ComponentName arg0) {
- }
- };
若要在AIDL中使用基本类型、String、CharSequence以外的数据类型,需要使用Parcelable,并指明方向。过程如下:
1、 定义一个类继承Parcelable,实现writeToParcel,以便将该类写入Parcel中(类似一个输出流)
2、 添加一个实现了Parcelable.Creator接口的名为CREATOR的静态变量
- public class MyParcelable implements Parcelable {
- int num;
- double n2;
- String string;
- public static final Parcelable.Creator<MyParcelable> CREATOR = new Parcelable.Creator<MyParcelable>() {
- public MyParcelable createFromParcel(Parcel in) {
- return new MyParcelable(in);
- }
- public MyParcelable[] newArray(int size) {
- return new MyParcelable[size];
- }
- };
- public MyParcelable() {
- }
- private MyParcelable(Parcel in) {
- num = in.readInt();
- n2 = in.readDouble();
- string = in.readString();
- }
- @Override
- public int describeContents() {
- return 0;
- }
- @Override
- public void writeToParcel(Parcel out, int flag) {
- out.writeInt(num);
- out.writeDouble(n2);
- out.writeString(string);
- }
- }
3、 创建一个MyParcelable.aidl文件,声明该类
- package com.learn.aidl;
- parcelable MyParcelable;
4、 在使用该类作为参数的aidl文件中import
- import com.learn.aidl.MyParcelable;
- interface MyAidl {
- MyParcelable getParcelable();
- void setParcelable(in MyParcelable myParcelable);
- }
- Service与AIDL讲解
- Service与AIDL详解
- Service与AIDL
- Android AIDL 与 Service
- Service与AIDL
- Android Service讲解 和 aidl 实现
- android笔记--Service与AIDL
- Service与Activity通信与AIDL
- Android:远程服务Service(含AIDL & IPC讲解)
- Android:远程服务Service(含AIDL & IPC讲解)
- AIDL 讲解
- Android--Service与AIDL(一)
- Android--Service与AIDL(二)
- Android Service与AIDL的使用
- Service AIDL
- service aidl
- service、aidl
- AIDL Service
- 黑马程序员——Objective-C 第二天课程学习总结
- 浅谈设计模式之二——Builder模式
- OS X系统审计子系统详解
- hdu 3349 lazy gege
- 由最小生成树(MST)到并查集(UF)
- Service与AIDL讲解
- <%@ attribute 中的参数使用jsp表达式来获取
- SVG 带有过渡效果的按钮
- Android数据库代码优化(2) - 从Cursor说起
- MySQL下load data相关问题
- 使用repo下载google 的android4.4 源码
- hdu 3498
- 【ObjectC】Xcode的常用快捷键
- ESIC Sr Resident & Specialist Final Results 2015