zoukankan      html  css  js  c++  java
  • 【朝花夕拾】四大组件之(二)Service篇

    一、Service是什么

           对于这个问题,想必大家都能说出一二,如“它是四大组件之一”、“在后台处理一些操作”等。咱们这里看看官方文档中的描述,官方语言一般都是准确且言简意赅的,这里可以体验一下其风格。如下是从官方文档中提取的关键部分,比较容易看懂,咱就不翻译了,详情可以阅读原文【What is a Service:https://developer.android.google.cn/reference/android/app/Service.html#what-is-a-service】。

    A Service is an application component representing either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use. 
    ......
    Thus a Service itself is actually very simple, providing two main features:
    ● A facility for the application to tell the system about something it wants to be doing in the background (even when the user is not directly interacting with the application). 
    ● A facility for an application to expose some of its functionality to other applications. 

          当笔者读到“perform a longer-running operation”的时候,深切感受到官网语言的准确性。因为笔者和很多开发者一样一般会说“在后台处理耗时操作”,显然这是不准确的,但是却找不到更好的语言来描述,知道看到官网的这句,有了“醍醐灌顶”的感觉。另外,如果以后在回答类似“Service是什么”的时候,咱们如果说“官网上说...第一点:XXX,第二点:XXX”,想必档次也会高不少吧!

    二、Service使用概述

           Service的使用是一种类似于C/S的形式,Service为Server端,正如第一节中提到的它的功能一样——在后台处理事务和向其他app提供功能,而调用服务的地方为Client端。由此可以看出,Service可以在app内部使用,也可以跨进程在不同的app中调用,对应的使用方法也略有不同,但整体上都是分为三个步骤:1)创建Service子类;2)在AndroidManifest.xml中声明;3)在Client端调用Service。后面会分不同的章节依次对这三步进行说明。

    三、Service在AndroidManifest.xml中的声明

           Service定义好以后,需要在AndroidManifest.xml中声明。这其中有很多可以定义的属性值,android开发者官方文档【<service>:https://developer.android.google.cn/guide/topics/manifest/service-element.html】中有详细的介绍。其给出的可以设置的属性有:

     1 <service android:description="string resource"
     2          android:directBootAware=["true" | "false"]
     3          android:enabled=["true" | "false"]
     4          android:exported=["true" | "false"]
     5          android:icon="drawable resource"
     6          android:isolatedProcess=["true" | "false"]
     7          android:label="string resource"
     8          android:name="string"
     9          android:permission="string"
    10          android:process="string" >
    11     . . .
    12 </service>

    其中有很多属性的含义,在笔者另外一篇文章【【朝花夕拾】四大组件之(一)Broadcast篇】第三节“广播的注册”的“静态注册中的属性简介”中介绍过,虽然是声明Broadcast Receiver的属性,但在Service中其含义基本上是一致的,这里就不赘述了。这里仅介绍一下之前没有介绍过的属性含义,主要是翻译官网中的内容并做一些补充。

    • android:description

           它是一个向用户描述该service的字符串。它应该被设置为对字符串资源的引用,使得它能够像其它用户界面中字符串那样本地化。

    • android:isolatedProcess

           如果被设置为true,该service将运行在一个特殊的进程中,该进程独立于系统的其他进成并且没有自己的权限。和该service通信的唯一方式就是 Servcie API(binding和starting)。

    • android:process

           在<application>及其它组件的声明中,都有该属性。这个属性在前面提到的广播篇中介绍过,这里补充说明一些内容。如果该进程以“:”打头,那么它的意思是指要在当前进程名称前面附加上当前的包名,如“:remote”表示当前进程为“packageName:remote”,它是当前app进程私有的一个进程,其他App的组件就不能和它运行在一个进程中。而如果以小写字母打头,如“com.remote”(官方文档中说命名规范中要求必须要含有".",否则会报错),则表示该进程名为“com.remote”,是一个全局进程,可以让不同app中的不同组件共享这个进程。

           对于如何正确使用多进程,为什么要用多进程,使用多进程有什么陷阱,在博文【Android多进程总结一:生成多进程(android:process属性)—https://blog.csdn.net/lixpjita39/article/details/77435156】中有更多的讲解,另外该篇文章所参考的文章也值得一读。

    Service的启动方式

    Service生命周期

    IntentService

    Service工作线程

    Service跨进程通信

    Service与子线程

           当提起Service的时候,很多人会联想到子线程,尤其对于初学者而言,甚至会把这两者的功能混为一谈,分不清楚这两者之间的区别。事实上,笔者在工作的前几年也没有很清楚地分清过它们的区别,所以这里就重点探讨一下这两者之间的联系、区别以及如何选择吧。

      1、Service和子线程的联系

           之所以会把这两者联系在一起,有很大一部分原因是它们都和后台和耗时扯上了关系。子线程是相对主线程而言的,在Android中,说到主线程就是指的UI线程,在UI线程中不允许处理耗时的操作,否则在系统规定的时间内会报ANR。耗时的操作如请求网络、操作数据库等就需要在子线程中去完成,所以子线程也被称为工作线程,相对于UI线程来说,子线程就是一个在后台运行的线程。而Service呢,在我们的认识当中,它也是用来处理一些后台任务的,一些需要长时间运行和比较耗时操作也会考虑放到这里运行,比如下载任务 ,播放音乐等。所以,如果没有一定的经验,确实是很容易混淆的。

      2、Service和子线程的区别

           事实上,如果没有做特别的处理,Service的生命周期函数在默认情况下都是运行在UI线程中的。Android这里提到的后台的概念,也是相对UI来说的,是指它的运行完全不依赖于UI,譬如正在使用的app就是一个前台进程,当按下Home键后,就变成了一个后台进程了。所以Service和子线程是没有半毛钱的关系的。既然Service是运行在UI线程的,那么它如何处理那些耗时操作的呢,难道不会阻塞UI线程发生ANR吗?事实上,这些耗时的操作也是在Service中开启子线程来完成的。

      3、Service与子线程的选择

           既然在Service中处理耗时操作也需要开启子线程,那为什么不直接在Acitivty中开启子线程,而非要多此一举开启服务然后再开子线程呢?这是因为Activity由于用户使用情况,经常会退出某个Activity去做其它操作,不会长时间停留在该Activity,如果在Acitivity中开了一个子线程,当Activity销毁以后,就没有办法再获取并控制这个子线程的实例了。而Service却可以长时间在后台运行,只要这个Service不被销毁,那么其他组件即便是销毁了,只要和该Service重新建立关联,就又能够获取到原有的Service中Binder的实例,对其中的子线程实例进行操作。

           当然,启用Service也不是一本万利的,因为Service是一个组件,势必要增到系统的开销,谷歌官方文档【https://developer.android.google.cn/guide/components/services#Basics】中也明确说明,应仅在必要时才创建服务。一般来说,如果是耗时不是太长的操作,且和activity有较多的交互,那么选择直接在Activity中开启子线程比较好。比如读取数据库中的数据并显示在界面上,以及获取网络数据并显示等,耗时不会太长且得到数据后要及时与activity交互,很明显就没有必要开启Service了。但是,如果像下载大文件这类需要较长时间完成的操作,就需要开启Service来完成了。Service也可以和界面交互,如前台Service,就会在通知栏上有和Service交互的界面。

           另外需要注意的是,这里所说的子线程,并不仅仅指传统的Thread类,还包括AsyncTask、HandlerThread等形式。

    不同版本中Service重要功能变迁

    android 8.0启动后台服务

     

    Service处理耗时操作

    https://blog.csdn.net/javazejian/article/details/52709857

    https://www.jianshu.com/p/95ec2a23f300

    https://developer.android.google.cn/reference/android/app/Service.html

  • 相关阅读:
    那些年搞不懂的多线程、同步异步及阻塞和非阻塞(一)---多线程简介
    java中IO流详细解释
    Java IO流学习总结
    MySQL数据库中索引的数据结构是什么?(B树和B+树的区别)
    使用Redis存储Nginx+Tomcat负载均衡集群的Session
    Redis 3.2.4集群搭建
    JDK1.8源码分析之HashMap
    java HashMap和LinkedHashMap区别
    Java中原子类的实现
    多线程-传统定时任务
  • 原文地址:https://www.cnblogs.com/andy-songwei/p/10422123.html
Copyright © 2011-2022 走看看