Android Service学习(一)

前言


在整理Android蓝牙开发的过程中,会用到后台播放音乐的功能,需要与service进行交互,因此对service作一个笔记,对以前未注意的细节作一次梳理。


一、service的基础知识


1.1 service的两种类型

  • started
    当应用组件,如Activity通过startService()启动service,此时service处于started状态。一旦启动,此时service能够在后台一直运行,即使启动它的组件已经被销毁。一般,启动服务执行单个操作,并且不会向调用者返回结果。当然这种情况视需求而定。
  • Bound
    当应用程序通过bindService()方法绑定到service时,service处于绑定状态。绑定服务可以为客户端-服务器提供接口,允许组件与service进行交互,发送请求,获得结果等操作,甚至还可以进行IPC(进程间通信)。仅当其他应用程序的组件与service绑定后,绑定服务才会允许。多个组件可以绑定到一个service上,并且当他们全部解除绑定时,service才可以被销毁。

1.2 service的线程

service运行于管理它的进程的主线程,即在APP内,service的线程id和主线程的id一致。可以使用log进行验证分别在MainActivity中的onCreate()中,以及自定义的MyService中的onCreate()中,执行Log

Log.e("TAG","主线程id = " + Thread.currentThread().getId());
Log.e(TAG,"Service的线程id = " + Thread.currentThread().getId());

得到的结果如下

06-21 03:49:28.491 5057-5057/com.example.slide_table E/MyService:主线程id=1

06-21 03:49:28.495 5057-5057/com.example.slide_table E/MyService:Service的线程id=1

如果需要在service中运行比较耗时的操作,可以在service中创建新的线程来完成这些操作,以减少应用可能出现的ANR。


二、service中的重要方法


在实际研发的过程中,几乎都需要对service中的回调方法进行重写以期达到需求。经常需要重写的几种回调方法如:

  • onCreate()
    服务第一次创建时,会执行这个函数,创一次性创建service,如果service已经存在,则不需要再次执行。

  • onStartCommand()
    当其他组件,例如activity调用startService()的方法请求启动service时,系统调用该方法,一旦执行此方法,service会一直运行于后台。同理,在服务完成后,如果需要停止service,可以调用stopSelf()或者stopService()方法停止service,如果用户只是想绑定service,则不需要重写该方法。

  • onBind()
    当其他的组件通过bindService()方法与service进行绑定,系统会调用该方法,但是在开发中必须通过返回IBinder提供客户端与service通信的接口,如果用户不想进行绑定,则返回null。

  • onDestroyed()
    当不需要service,需要对service进行销毁的时候调用该方法,服务应该利用该方法来实现清理线程,注册监听器等资源,这也是service收到的最后一个方法调用。需要注意的是用户是通过startService()启动该service时(此时service会调用onStartCommand()),服务调用stopSelf()方法停止自身。或者其他的组件使用stopService()来停止该service。

当用户的系统内存不足时,必须回收系统资源来显示用户关注的activity时,才会停止service的运行。但是若此service为用户关注的activity所绑定的,则会减少回收的几率。如果服务被声明运行于前台,则基本不会停止。
如果service处于started状态,虽然会一直运行于后台,但是为了降低这种系统资源被回收的风险,需要对重启该service进行设计。当系统资源变得充足可用时,可重新启动该service,但是依赖于onStartCommand()的返回值。


三、service配置的几种属性


当在开发中声明某service时,必须在AndroidManifest.xml中对该服务进行配置。常用的几种属性为:

  • android:name
    实现该service的名称,一个完整的类名,通常简写为".MyService"。

  • android:enabled
    服务能否被系统实例化,可以则返回true,or false,默认为true。

  • android:exported
    其他组件能否调用服务或者与其交互,可以则返回true,or false。当表示false时,只有该APP内的应用组件或者与APP具有相同用户ID的APP能启动或者与之绑定。

  • android:label
    显示给用户的service名称,如果没有设置,以应用程序APP的标签取代。

  • android:permission
    实体必须包含的权限名称,如果没有设置该属性,可以使用<application>标签的permission属性设置服务权限。


四、service的创建


通过继承创建service,Android提供以下两个类供开发继承:

4.1 Service

所有service的基类,当继承该类时,创建新的线程来处理需要执行的动作,避免出现ANR的情况。特点:

  • 可以实现服务处理多线程的任务
  • 每次请求创建一个新线程并且立即执行,不用等待前一个请求的结束

4.2 IntentService

该类为service的子类,每次都会使用一个工作线程来处理全部的启动请求。在APP中如果不是处理多个请求,最优的创建服务继承该类。开发人员只需要重写onHandleIntent()方法,来执行接收到的intent,从而完成后台服务。
特点:

  • 创建工作线程来执行发送到onStartCommand()的全部intent
  • 创建工作队列,一次传递一个Intent给onHandleIntent()
  • 避免出现多线程
  • 所有启动service请求完毕后,自动停止service,不需要调用stopSelf()停止该service
  • 提供的onBind()方法默认实现,返回null
  • 提供onStartCommand()方法默认实现,先将intent发送给工作队列,然后在发送给onHandleIntent()执行
  • 只需要在onHandleIntent()执行客户端提供的任务

注意:IntentService并没有提供构造函数,因此在继承IntentService后,需提供一个无参的构造方法。

public class MyIntentService extend IntentService{
    public MyIntentService(){
        super("MyIntentService ");
    }
}

五、service中的重要函数


onStartCommand()
在组件请求启动service后,会发送Intent,服务开启后,调用onStartCommand()方法执行该任务。

但是该方法必须返回一个整数,用于描述系统停止service后如何继续服务,此点仅在继承自service的服务中使用,因为继承IntentService已经默认实现。返回值:

  • START_NOT_STICKY
    在执行onStartCommand()完成任务后,停止该service,不重新创建服务,则返回
  • START_STICKY
    在执行onStartCommand()完成任务后,停止该service,重新创建服务,并且再次调用onStartCommand(),但是不重新发送最后的Intent。相反,系统使用空Intent调用onStartCommand(),除非有PendingIntent来启动该service,此时这些Intent会被发送。
    此返回值经常用于多媒体播放器,它们不执行命令,但无限期的运行并等待命令。
  • START_REDELIVER_INTENT
    在执行onStartCommand()返回后停止该service,重新创建服务,并使用发送给服务最后的Intent重新调用onStartCommand(),全部的PendingIntent依次发送。此返回值适用于积极执行并且立即恢复工作的服务,如wifi模式下后台下载文件,断开wifi后,文件下载中断,重新打开wifi,继续下载文件。

六、service的启动与停止


6.1 service的启动

service的启动分为传递intent启动以及绑定启动,本章主要讲述通过传递intent来启动service。
通过activity或者其他应用组件来传递Intent来启动service,系统调用service的onStartCommand()并且将该Intent传递给它。

Intent service_intent = new Intent(MAcitivty.class, MyService.class);
startService(service_intent);
/**
    如果activity与fragment交互,需要使用
    getActivity().startService(service_intent);
*/

如果service没有提供绑定,则startService()发送的intent是APP的组件与该service唯一的通信模式。如果需要服务返回结果,则启动该服务的客户端能为广播创建一个PendingIntent,并且通过启动service的Intent进行传送。服务便可以通过广播来发送结果。

6.2 service的停止

通常情况下,APP在服务完成任务后,应该停止服务,避免造成系统资源的浪费和电池的消耗。系统不会自动的停止或者销毁服务,除非系统资源紧缺需要系统资源的回收,而且还可以在onStartCommand()返回后,服务继续运行。service本身可以调用stopSelf()停止自身,或者其他的应用组件调用stopService()来停止该service。

注意,如果该service同时处理多个onStartCommand()的调用请求,在处理一个请求后,首先需要判断另一个新的请求的ID是否与上一个请求的ID是否相同,即在使用stopSelf(int)方法停止该服务时,同时将新的启动service的请求ID传递给停止请求进行匹配,如果下一个新的请求的ID与上一个请求的ID不相同,则不会停止本次的服务,这样就会避免多次启动服务的请求,而多次调用onStartCommand()。

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

推荐阅读更多精彩内容