首页 > 其他 > 详细

[03] 四大组件之Service

时间:2015-03-23 11:06:21      阅读:272      评论:0      收藏:0      [点我收藏+]

一、基本概念

服务,四大组件之一,主要处理一些需要在后台长期运行的任务或耗时较长的操作,无用户界面。服务可以被其它应用程序组件启动,也可以被其它组件绑定使用(Activity、服务、ContentProvider),还能进行进程间通信(IPC).
 
二、Service的基本用法
作为四大组件,需要在AndroidManifest.xml中的<application>节点下配置<service>。
新建一个Service类子类(或继承一个已有Service的子类)。重写一些重要的回调方法...
  • onCreate()
当服务第一次创建时调用,用于执行服务的一些一次性配置工作,如果之前已经系统已经调用过onStartCommand()或onBind()了,即服务已经运行了,该方法不会再被系统调用,也就是Service的onCreate()方法在一个生命周期内只会调用一次,无论后续启动它多少次。
  • onStartCommand()
当其它组件调用startService()启动服务时,系统将会调用本方法。多次startService, onStartCommand()会被多次调用。服务启动后将会在后台一直运行下去,哪怕应用程序已经退出前台甚至关闭,所以我们有责任在Service的任务完成时调用stopSelf()或stopService()终止服务(当然这是在该服务未被绑定情况下)。
  • onBind()
当其它组件通过bindService()绑定服务时,系统调用该方法,该方法将会返回一个IBinder对象,客户端通过IBinder可以与服务进行通信,比如访问IBinder的接口或Service的公共方法。如果不需要绑定,返回null便是。
  • onUnbind()
被解除绑定时调用,通过unbindService()。
  • onReBind()
客户端已经解除过绑定一次,但又重新去bindService时调用。返回类型void,但会重新传出IBinder对象。
  • onDestroy()
服务已被stop或unbind后,已经不需要并要销毁时调用该方法。可以在此方法中进行资源清理的工作,比如线程、listener等。
 
Service的启动方式:(结合生命周期回调方法看)
1、started
        其它组件通过startService(intent)启动服务,服务的onCreate()onStartCommand()生命周期回调函数将被调用,该服务便被"started"了。一旦服务被启动,便会一直在后台运行下去,及时启动它的组件已经被销毁。所以使用该启动方式的服务通常用来执行单一的操作,且不会向调用者返回结果。比如下载/上传,文件I/O。操作完成后,服务应该自行终止stopSelf(),或调用者记得stopService()。服务终止后系统调用onDestroy()函数[注:一旦服务创建但未被销毁,多次调用startService()只会执行生命周期的onStartCommand()方法。]
        生命周期:onCreate()--->onStartCommand()--->onDestroy()
2、bound
        如果某个组件需要和Service进行通信,则可以通过与服务绑定方式进行通信。即客户端通过调用bindService()绑定到服务上,bound的服务会调用onCreate()--->onBind()返回一个IBinder对象,通过该对象可与服务进行交互、发送请求、获取结果等。绑定的服务于被绑定的客户端组件的生存期一致。客户端调用unbindService()与服务解除绑定,服务回调unBind()方法,当所有绑定解除后,服务被销毁,调用onDestroy()方法。
        生命周期:onCreate()--->onBind()--->onUnbind()--->onDestroy()
3、started和bound相结合
        任何一个被启动的Service都可以被绑定。所以终止服务时,记得先解除绑定在再stopService(),否则Service无法销毁。

三、前台Service
运行在后台Service在内存偏低的情况还是有可能被系统回收的,并且有些服务是需要经常被用户关注或使用的,比如说墨迹天气在状态里的天气信息,MIUI的音乐播放器播放music时也在状态栏显示当前播放歌曲信息并提供操作接口,像这类服务的优先级较高。所以我们可以把这类服务提高优先级为前台服务,它在内存过低时也不会成为被杀对象。
创建前台服务需要一个挂起的通知栏对象。在Service的onCreate()方法中创建Notification,然后调用startForeground()方法便可以让该Service成为一个前台Service,代码示例如下:
Notification notification = new Notification(R.drawable.icon,
        getText(R.string.ticker_text), System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
        getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION, notification);

 

四、Service与Thread
首先澄清两者没有关系!一个是运行在后台应用程序组件,一个是线程,两个不同的概念。Service运行在主线程里,所以在服务中执行密集计算或阻塞操作时,仍需要在服务中创建一个子线程来完成。有人可能问,那这些事情何不直接在Activity中创建一个子线程去干?这是因为Activity很难对Thread进行长期控制与跟踪,比如音乐播放器,Activity销毁了,或切换至其他Activity了,那么创建子线程的实例便消失了,或上下文已经不同了,无法进行控制。但Service就不同了,所有的Activity都可以Service进行关联,可以方便地操作其中的方法,即使Activity被销毁,只要重新建立与Service的连接,就又可以获得原有的Service中的Ibinder实例,然后操作其中的方法。因此,用Service来处理后台任务,Activity可以放心的finish,无需担心对后台任务进行控制的情况。
 
五、IntentService
IntentService是Service的子类,用来多个请求的异步方案。IntentService在onCreate()函数中通过HandlerThread单独开启一个线程来处理所有的intent请求,如果之前的任务未完成,新的请求会放入队列,但任务完成在执行下一个请求,如果所有请求都处理完成,则自动终止Service。使用IntentService只需两个步骤:
1、创建一个参数为空的构造函数,然后调用super("serviceName");
2、实现onHandleIntent(),这里根据不同的intent处理不同事务便可。
 
六、远程Service
远程,即使用其它进程的Service,这边是跨进程通信了(IPC)。使用AIDL(Android Interface Definition Language),Android接口定义语言。简单梳理一下AIDL的大致流程:
0、远程Service在manifest.xml中的配置需加入属性 android:process=":remote",如果需要加入意图过滤;
1、在远程服务端新建一个aidl的文件,类似于接口的定义,里面可声明一些供其它进程调用的方法;
2、保存aidl文件,项目会自动生成一个java文件;
3、在Service类里实现刚定义好的aidl接口,即实现MyAIDL.Stub对象,MyAidl.Stub实际上市Binder的子类;
4、在Service类的onBind()方法里返回Stub的实现;
5、把aidl文件copy至Client端工程;
6、在Client端的ServiceConnection实现中,当Service连接时,把返回的IBinder对象asInterface()成远程服务对象;
7、调用其中的方法便可使用。

 

[03] 四大组件之Service

原文:http://www.cnblogs.com/ddd2014/p/4359021.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!