二 Service总结

只是写一遍加深印象。

1 概述

一种后台服务。使用时需要在Manifest声明。
两种使用方式:

  1. 启动模式。适用于Service不需要与启动组件交互的场景。
  2. 绑定模式。适用于Service需要与启动组件交互的场景,当解除此类Service的所有绑定者后,Service也被销毁。

2 声明

使用Service前需要在Manifest中声明,其属性有:

  1. exported[true|false]。是否支持隐式调用。
  2. name
  3. permission
  4. process[:xxx|xxx]注意这里的冒号,有冒号代表进程名为“包名:xxx”,无冒号代表进程名为不加包名前缀的“xxx”。
  5. isolatedProcess[true|false]。进程与其他进程分开且无权限,通信只能通过Service的API(bindstart)。
  6. enable。父标签(若有)和子标签必须同时为true,该服务才有效。

3 启动服务

3.1 startService启动

这种方式启动的Service不会随着启动者的退出而停止,可以用stopService(Intent)或者服务自身调用stopSelf停止。
每次启动都会调用onStartCommand

需要关注的方法

  • onCreate
    首次创建Service时回调此方法,之后不会再回调。

  • onStartCommand(Intent intent,int flag,int startId)
    startService时会回调,然后启动服务。

    • @params
      intent是启动服务时的传参。
      flag有三个值:
      1.0,无参数。
      2.START_FLAG_REDELIVERY。代表本方法的返回值为 START_REDELIVER_INTENT,当service因内存不足被系统关闭后,会 用最后一个传入的intent作为参数再次调用本方法(onStartCommand)。
      3.代表当本方法调用后一直没有返回值时,会重新调用本方法。
      startId当前服务id。
    • @return
      三个可选值:
      1.START_STICKY。Service因内存不足被杀死后,尝试重新创建此服务并回调onStartCommand,传入intent为空(除非有挂起的pendingIntent)。适用于无限期运行等待作业的播放器等。
      2.START_NOT_STICKY。不重启。
      3.START_REDELIVER_INTENT。重启并传递最后的intent。适用于恢复下载等。
  • onDestroy
    在这里清理所有资源。

3.2 bindService启动

Service处于绑定状态时,相当于“client-server”模型中的server,client通过代理与server交互。
绑定的Service的生命周期与宿主绑定,宿主退出即服务销毁。
显然,在绑定服务时必须提供IBinder接口的实现。

定义Service接口的三种方法

1.扩展Binder类。
client通过binder调用service提供的能力。常用于service作为本应用的后台线程的情况,比如下载、播放等。
唯一不适用的场景是service需要提供给其他app调用。
2.使用Messenger
Messenger用于跨进程传递数据(基于Handler、AIDL,本质是封装之后的AIDL),可以使用其为服务定制接口。
Messenger串行处理客户端发来的消息(线程安全)。
3.使用AIDL
允许同时处理多个跨进程的请求。
一般同时采用线程安全式设计。使用时需要自定义.aidl文件。SDK工具利用该文件生成实现接口并处理IPC的抽象类,随后对其进行扩展。

3.2.1 扩展Binder类

1.在Service的子类(目标业务类)中创建一个实现Binder接口的实例对象,并实现公共方法用于客户端调用
2.onBind()回调返回此Binder实例;
3.在客户端中,从onServiceConnected()回调方法接收Binder,并用提供的方法调用服务的能力。

典型场景是后台音乐服务。服务和客户端必须在同一进程内。

// flag 0代表不创建service,BIND_AUTO_CREATE代表绑定时自动创建service
bindService(intent,conn,Service.BIND_AUTO_CREATE);



conn = new ServiceConnection() {
    /**
     * @param name 封装组件的描述信息,很少使用
     * 与服务器端交互的接口方法 绑定服务的时候被回调,在这个方法获取绑定Service传递过来的IBinder对象,
     * 通过这个IBinder对象,实现宿主和Service的交互。
     */
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.d(TAG, "绑定成功调用:onServiceConnected");
        // 获取Binder
        // 注意这里是将IBinder接口强转为Binder实现类
        LocalService.LocalBinder binder = (LocalService.LocalBinder) service;
        mService = binder.getService();
    }
    /**
     * 当取消绑定的时候被回调。但正常情况下是不被调用的,它的调用时机是当Service服务被意外销毁时,
     * 例如内存的资源不足时这个方法才被自动调用。
     * 当客户端取消绑定,不会回调此方法
     */
    @Override
    public void onServiceDisconnected(ComponentName name) {
        mService=null;
    }
};

多次调用bindServiceunbindService,对应的onBindonUnbind也只会回调一次。
绑定方式的service生命周期为onCreate->onBind->onUnbind->onDestroy

3.2.2 Messenger

用于不同进程间的通信。如果需要互相发送消息,需要在服务端和客户端都布置Messenger和Handler。大致过程如下:
1.服务端实现Handler,用于接收客户端的回调;
2.使用上述Handler创建Messenger
3.用Messenger创建IBinder,在serviceonBind方法中,将其返回客户端;return mMessenger.getBinder();
4.客户端收到IBinder后,用其实例化Messengernew Message(iBinder)),用其发送Message
5.MessengerHandler中(handleMessage())接收Message并处理。

messenger.jpg

3.2.3 绑定服务注意

1.多个客户端可以同时绑定一个服务,只有首次绑定回调onBind,其余情况系统会自动传递IBinder;除非startService也启动了该服务,否则最后一个客户端取消绑定时,服务被销毁。
2.应该在客户端的引入和退出时刻绑定、注销服务。只需要在activity可见时存在的服务应绑定在onStartonStop;需要在activity存活期间都运行的服务,应该绑定在onCreateonDestroy,并且应该提高进程的权重。
3.不应该在onPauseonResume期间绑定、取消绑定,它们太频繁,并且可能引起服务的销毁和重建
4.远程方法可能引起DeadObjectException,由连接中断引发,表示调用的对象已死亡(service对象已销毁),这是远程方法的唯一异常,继承RemoteException
5.bindService方法内部,系统会调用服务的onBind方法,返回用于与服务交互的IBinder该方法是异步的

3.2.4 启动服务、绑定服务的优先级问题

startService(启动服务)的优先级大于bindService(绑定服务)。若同时启动、绑定了服务,在调用stopService或者stopSelf之前,即使所有客户端都取消绑定了,服务在完成前也不会停止。
同样,在仍有客户端绑定在服务上时,stopService或者stopSelf也不会停止服务。

3.3 服务在其托管进程的主线程运行

如果需要进行耗时操作,需要另起新的线程。

3.4 前台服务以及通知

前台服务在状态栏提供无法清除通知(除非服务停止或者从前台删除),例如音乐播放器。
两个相关的方法:
1.startForeground(int id,Notification)。参数显然为标识id(不得为0)和通知。
2.stopForeground(boolean removeNotification)
从前台删除服务并删除通知。

3.5 常见使用场景

下载文件,service后台执行,notification前台显示,thread异步下载。
app维持service从网络获取推送服务。
这里引入讨论IntentService

3.6 生命周期

service_life.jpg

3.7 显示、隐式启动

  • 显示启动
Intent  intent=new Intent(this,xxxService.class);
startService(intent);
  • 隐式启动
    主要用于启动其他应用的Service。
    Intent设置action,可以是服务的全路径名,此时android:exported默认为true
Intent intent=new Intent();
intent.setAction("com.android.xxxService");
startService(intent);

隐式启动在4.4版本会警告,5.0以上会抛异常,因为隐式声明intent去启动Service是不安全的。

  • 需要同时设置action和packageName
    就是加上
intent.setPackage(getPackageName());//设置应用包名
  • 转换为显式启动
    需要为intent设置component再启动服务。
public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
    // Retrieve all services that can match the given intent
     PackageManager pm = context.getPackageManager();
     List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
     // Make sure only one match was found
     if (resolveInfo == null || resolveInfo.size() != 1) {
         return null;
     }
     // Get component info and create ComponentName
     ResolveInfo serviceInfo = resolveInfo.get(0);
     String packageName = serviceInfo.serviceInfo.packageName;
     String className = serviceInfo.serviceInfo.name;
     ComponentName component = new ComponentName(packageName, className);
     // Create a new intent. Use the old one for extras and such reuse
     Intent explicitIntent = new Intent(implicitIntent);
     // Set the component to be explicit
     explicitIntent.setComponent(component);
     return explicitIntent;
    }

参考文章

zejian_-关于Android Service真正的完全详解,你需要知道的一切

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

推荐阅读更多精彩内容

  • 【Android Service】 Service 简介(★★★) 很多情况下,一些与用户很少需要产生交互的应用程...
    Rtia阅读 3,140评论 1 21
  • 上篇我们讲解了Android中的5中等级的进程,分别是:前台进程、可见进程、服务进程、后台进程、空进程。系统会按照...
    徐爱卿阅读 3,843评论 6 33
  • 绑定服务: 绑定服务是客户端-服务器接口中的服务器。绑定服务可让组件(例如 Activity)绑定到服务、发送请求...
    pifoo阅读 1,220评论 0 4
  • 什么是Service Service是一个可以在后台长时间执行的应用组件。 Service的启动方式 startS...
    MGLEE阅读 356评论 0 0
  • Singleton pattern 限定类对象只有一个实例核心原理是将构造函数私有化,并且通过静态方法获取一个唯一...
    wangdy12阅读 174评论 0 0