Service总结

什么是serice:

Service可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC) (可以通过将服务声明为私有服务,并阻止其他应用访问)。

Service一般分为两种形式,一种用于执行一些下载文件等操作,不需要与用户进行交互,当应用组件(如Activity)通过调用 startService() 启动服务后,服务便与启动它的组件已无关联,服务会一直在后台运行,直到它负责的任务完成,服务会自动停止运行。一种是与应用组件进行绑定(调用bindService()),比如要做一个后台播放音乐,界面UI变化需要和音乐进度交相呼应的时候,就需要让服务与该应用界面进行绑定。多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。

服务可以同时以这两种方式运行,它既可以是启动服务(以无限期运行),也允许绑定。只要实现了onStartCommand()(允许组件启动服务)和 onBind()(允许绑定服务)这一组回调方法。注意:服务是不会自己开辟一个新线程的,若执行一些耗时操作,请手动开辟一个新线程。

何时使用服务:

服务是一种即使用户未与应用交互,但它仍可以在后台运行的组件。如需在主线程外部执行工作,不过只是在用户正在与应用交互时才有此需要,则应创建新线程而非服务。若只想在一个activity运行的同时,则可在 onCreate() 中创建线程,在 onStart() 中启动线程,然后在 onStop() 中停止线程,或者用AsyncTask 或 HandlerThread,而非传统的 Thread 类。使线程与activity同存亡即可,不必开启一个服务。

如何实现service:

为了确保应用的安全性,请始终使用显式 Intent 启动或绑定 Service,且不要为服务声明 Intent 过滤器。 启动哪个服务存在一定的不确定性,而如果对这种不确定性的考量非常有必要,则可为服务提供 Intent 过滤器并从 Intent 中排除相应的组件名称,但随后必须使用 setPackage() 方法设置 Intent 的软件包,这样可以充分消除目标服务的不确定性。还可以通过添android:exported 属性并将其设置为 "false",确保服务仅适用于您的应用。

创建服务的两种方法:

1.Service:这是适用于所有服务的基类。

Intent intent = new Intent(this, myService.class);

startService(intent);//以此方式启动,无法获知service做什么

Intent intent = new Intent(this, myService.class);

bindService(intent,serviceConnection, BIND_AUTO_CREATE);//BIND_AUTO_CREATE表示创建尚未激活的服务.其他可能值为 BIND_DEBUG_UNBIND 和 BIND_NOT_FOREGROUND或0(表示无)。

private ServiceConnection serviceConnection = new ServiceConnection() {

@Override

public void onServiceDisconnected(ComponentName name) {

//Android 系统会在与服务的连接意外中断时(例如当服务崩溃或被终止时)调用该方法。

}

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

  myBinder = (MyBinder) service;

//myBinder是该活动和服务相通的地方,但在执行此代码之前,活动生命周期需已变为可见

} };

public class myService extends Service {

@Override

public IBinder onBind(Intent intent) {

return myBinder;//回调,提供给活动MyBinder的对象

}

public class MyBinder extends Binder {

//可供绑定的activity调用的方法

//个人浅见,此类中的方法有点类似于接口的作用,仅代表用来和活动通信,切勿将过多的逻辑代码放在里面。影响程序的可读性

} }

unbindService(mConnection);//当客户端被销毁时,它将取消与服务的绑定,但始终应该在完成与服务的交互或Activity 暂停时取消绑定,以便服务能够在未被占用时关闭。

stopService(intent);//记得将后台程序关闭,特别是又启动又绑定时。

绑定是异步的。bindService()会立即回,“绝对不会”使IBinder返回客户端。要接收IBinder,客户端必须创建一个ServiceConnection实例,并将其传递给 bindService()。ServiceConnection 包括一个回调方法,系统通过调用它来传递 IBinder。

注意:1.要时刻记得service要想更改UI时,要用Handler,因为他们身处两个线程中。

        2.只有 Activity、服务和内容提供程序可以绑定到服务,广播接收器无法绑定到服务。

2.IntentService:这是 Service 的子类,它使用工作线程逐一处理所有启动请求。如果不要求服务同时处理多个请求,这是最好的选择。 只需实现 onHandleIntent() 方法即可,该方法会接收每个启动请求的 Intent。

IntentService 执行以下操作:

•创建默认的工作线程,用于在应用的主线程外执行传递给 onStartCommand() 的所有 Intent。

•创建工作队列,用于将一个 Intent 逐一传递给 onHandleIntent() 实现,这样永远不必担心多线程问题。

•在处理完所有启动请求后停止服务,因此不必调用 stopSelf()。

•提供 onBind() 的默认实现(返回 null)。

•提供 onStartCommand() 的默认实现,可将 Intent依次发送到工作队列和onHandleIntent() 实现。

只需要一个构造函数和一个 onHandleIntent() 实现即可。并且无需从中调用超类的唯一方法就是 onBind()(仅当服务允许绑定时,才需要实现该方法)。

public class MyService extends IntentService {

public MyService() {

super("MyService");

}

@Override

protected void onHandleIntent(Intent intent) {

//我们通常会做一些工作,比如下载一个文件。为示例,我们只睡5秒。

long endTime = System.currentTimeMillis() + 5*1000;

while (System.currentTimeMillis() < endTime) {

synchronized (this) {

try {

wait(endTime - System.currentTimeMillis());

} catch (Exception e) {

}

} } } }

服务的生命周期:


左:由startService() 创建,右:由bindService() 创建

服务生命周期(从创建到销毁)可以遵循两条不同的路径:

1.启动服务:该服务在其他组件调用 startService() 时创建,然后无限期运行,且必须通过调用 stopSelf() 来自行停止运行,或者其他组件通过调用 stopService() 来停止服务。服务停止后,系统会将其销毁。

2.绑定服务:该服务在另一个组件调用 bindService() 时创建。然后,客户端通过 IBinder 接口与服务进行通信。客户端可以通过调用 unbindService() 关闭连接。多个客户端可以绑定到相同服务,而且当所有绑定全部取消后,系统即会销毁该服务。 (服务不必自行停止运行。)

这两条路径并非完全独立。例如,可以通过使用 Intent(标识要播放的音乐)调用 startService() 来启动后台音乐服务。随后,Activity 可以通过调用 bindService() 绑定到服务。在这种情况下,除非所有客户端均取消绑定,否则 stopService() 或 stopSelf() 不会真正停止服务。

通过实现这些方法,您可以监控服务生命周期的两个嵌套循环:

•服务的整个生命周期从调用 onCreate() 开始起,到 onDestroy() 返回时结束。与 Activity 类似,服务也在 onCreate() 中完成初始设置,并在 onDestroy() 中释放所有剩余资源。

•服务的有效生命周期从调用 onStartCommand() 或 onBind() 方法开始。每种方法均有 Intent 对象,该对象分别传递到 startService() 或 bindService()。

对于启动服务,有效生命周期与整个生命周期同时结束(即便是在 onStartCommand() 返回之后,服务仍然处于活动状态)。对于绑定服务,有效生命周期在 onUnbind() 返回时结束。

注:尽管启动服务是通过调用 stopSelf() 或 stopService() 来停止,但是该服务并无相应的回调(没有 onStop() 回调)。因此,除非服务绑定到客户端,否则在服务停止时,系统会将其销毁—onDestroy() 是接收到的唯一回调。

图 2 说明了服务的典型回调方法。尽管该图分开介绍通过 startService() 创建的服务和通过 bindService() 创建的服务,但是请记住,不管启动方式如何,任何服务均有可能允许客户端与其绑定。因此,最初使用 onStartCommand()(通过客户端调用 startService())启动的服务仍可接收对 onBind()的调用(当客户端调用bindService() 时)。

IntentService与Service

1. IntentService比Service好在哪?

IntentService 是继承于 Service 并处理异步请求的一个类,在 IntentService 内有一个工作线程来处理耗时操作,启动 IntentService 的方式和启动传统 Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在IntentService 的 onHandleIntent 回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。

2. IntentService 为什么可以处理耗时任务? 

应该从源码上面来分析,IntentService 是直接继承与 Service的,内部在 onCreate()时,新建了一个HandlerThread 实例。

(HandlerThread 是一个Thread的 子类,HandlerThread 内部 有点线我们的UI线程,内部一个Looper loop循环一直轮询消息 获得消息 处理消息。)

而IntentService, 内部有一个Handler子类 ServiceHandler,它的Looper用的是这个HandlerThread 的Looper,IntentSerivce 在onStart()通过发送Message,ServiceHandler在处理Message 调用的是 onHandleIntent。

所以简单的说一个IntentService,内部就创建了一个线程,通过Android提供的 Handler Message Looper,这些消息处理的类构成了一个消息处理的模型。所以IntentService 的onHandleIntent 这个方法其实是在IntentService 中开辟的一个子线程中处理的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容