Android中Service深入学习
概述
1、当用户在与当前应用程序不同的应用程序时,Service可以继续在后台运行。
2、Service可以让其他组件绑定,以便和它交互并进行进程间通信。
3、Service默认运行在创建它的应用程序的主线程中。
Service的使用主要是因为应用程序里面可能需要长时间地运行一些任务但是又不需要用户界面或者应用程序本身需要对外提供一些函数给其他的应用程序调用。每一个Service实体类必须相应地在它的包中的AndroidManifest.xml有一个<service>
配置节的声明。Services可以用 Context.startService()
或Context.bindService()来启动。
下面我们将会涉及到几个主题:
1、什么是Service?
2、Service的生命周期
3、进程生命周期
什么是Service?
很多Android的初学者都对Service抱有浓浓的疑惑,Service到底是什么,但是似乎更多的问题是Service到底不是什么?
- Service不是一个独立的进程。Service不像他的名字所暗示的,它没有自己独立的进程;除非另外指定,Service运行在跟应用程序相同的进程中,并且他是应用程序进程的一部分。
- Service不是一个线程。但也不是说Service就运行在界面主线程(Main Thread)中( Android中为了避免应用程序没有响应的错误)。
其实Service非常简单,它主要有两个特性:
- 它是一种应用程序跟系统进行沟通的机制,告诉系统有一些任务要在后台运行(即在用户使用应用程序的时候)。我们可以对应地调用
Context.startService()
让系统运行Service,Service会一直运行,直到Service本身或者其他人显式地停止它。 - 它是一个应用程序对外(其他应用程序)暴露函数接口的机制。我们可以对应地调用
Context.bindService()来运行,这样子其他的应用程序就可以长时间地跟Service连接,进行一些交互。
在一个Service组件被创建的时候,系统做的工作其实就是在主线程上实例化Service组件,然后调用Service的
onCreate()还有其他Service的回调函数而已。也就是说,可以认为系统除了调用一下Service的函数,其他什么都不会再做了,如果你想要运行什么长时间的任务,比如从网络上下载文件,那么跟以前一样,你需要自己写一个线程,当然是在Service内对应的函数中。
不过正因为Service本身如此简单,我们可以自由定义Service,使之与外界进行一些简单或者复杂的交互。我们可以将Service视为本地Java对象,进行直接的方法调用(具体的示例见Local Service Sample),也可以通过AIDL提供一个完全的远程接口。
Service的生命周期
Service是由Android系统进行调度的。如果有人调用Context.startService(),系统就会将Service取回(有必要的时候创建它,并调用它的
onCreate()
方法)然后调用它的onStartCommand(Intent, int, int)
方法,使用客户端提供的参数。这时候,Service会继续运行运行直到Context.stopService()
or stopSelf()被调用。注意:我们可以多次调用Context.startService()不会发送嵌套调用(尽管会有多次onStartCommand()的响应),所以不管Service多少次被启动,它都只会在一次Context.stopService() 或stopSelf()的调用中被停止。然而,service可以使用它的
stopSelf(int)方法来保证自己不会被停止,直到启动它的intents被处理完。
对于一个启动的服务(started Service)有两种操作模型,这决定了它们不同的运行方式,而运行方式由它们的OnStartCommand()函数的返回值决定。
START_STICKY适用于一个服务需要被明确地指定启动或停止的情况。而while
START_NOT_STICKY
或START_REDELIVER_INTENT使用于一个服务需要一直运行直到处理完它们收到的命令。
客户端也可以使用
Context.bindService()
去取得与一个Service的长连接。它同样会创建一个Service,如果Service没有运行(调用onCreate()
来创建),但不会调用onStartCommand()。客户端将会接收从service的onBind(Intent)方法返回的
IBinder对象,从而客户端就可以调用service上的方法了。只要客户端和service的连接一建立,service就会一直保持运行状态(无论客户端是否有保存service的IBinder引用)。通常IBinder返回的是一个用aidl写好了的复杂接口。
一个service可以同时被启动和绑定。在这种情况下,系统会保持一个带有
Context.BIND_AUTO_CREATE 标识的service一直运行只要他被启动或者有一个或多个连接跟这个服务绑定着。一旦没有被启动和连接,service的
onDestroy()就会被调用然后service就会被终止。在
onDestroy()方法返回前,所有的线程和资源都应该被清理掉。
Process Lifecycle
前面我们讲到,Service其实是运行在寄居在应用程序的进程当中的,也就是说当应用程序的进程被销毁的时候,Service也就被销毁了。当然,Android系统会尽力保证带有Service的应用程序进程存活尽可能长的时候,只要进程中有Service已经启动或者有别的客户端需要使用着Service的服务。当Android系统内的内存不足,需要杀死一些进程来释放内存时,在下面情况中,线程的优先级会因为Service而增高,进而减少被系统回收的可能性:
如果进程中的Service正在执行onCreate()
,onStartCommand()
, 或onDestroy()方法,那么这个进程就会变成前台处理(foreground process)进程,进而能够保证进程不会被回收。
如果一个Service被启动了,那么他的宿主进程就会被系统认为比当前用户正在使用的的应用程序的进程更不重要,但比其他的后台进程更重要。因为通常用户当前只使用一小部分进程(也就是用户看得见的进程),这意味着Service所在的进程不应该被回收掉,除非系统内存极度缺乏。
如果一个客户端(Client)跟Service绑定,那么这个Service的宿主进程会被系统认为跟客户端进程是同等重要的,也就是,如果一个客户端程序对用户是可见的(也就是正在被使用),那么Service自身也会被认为是可见的。
已经开始运行了的Service可以使用startForeground(int, Notification) API将当前进程放到前台状态(Foreground state),这样系统就会认为他是用户想要使用的进程,因此就不会成为低内存时的待回收进程。(但是理论上,在内存极度匮乏的情况下,这个进程仍有可能被回收。实际上,一般不会有这么极端的情况)。
注意,这说明当我们的Service正在运行的时候,它都不会被系统杀死,除非内存快满了。如果Service被杀掉了,那么随后系统还会尝试着重新启动Service。这样子,我们就必须考虑到如果我们实现
onStartCommand()方法,用异步或者其他线程来完成Service的任务,那么我们就可能需要使用
START_FLAG_REDELIVERY
让系统重新传递一个Intent,以便在Service重新启动后,Intend会丢失。
在同一个进程中的应用程序组件(application components)像Service(或者Activity)可以增加进程在所有进程中的重要性,而不是仅仅增加Service的重要性。
补充说明:
前面谈到Service是由系统进行调度的,那么对我们来讲有什么意义呢?他又体现在什么地方呢?
因为Service是由系统进行调度的,那么它的生命周期与Activity的生命周期也就无关了,也就是假设ServiceA是由ActivityA启动的,即使当ActivityA因为某种原因调用了OnDestroy()方法将自己销毁掉之后,ServiceA依然欢快地运行着。
Android中Service深入学习的更多相关文章
- Android中Service(服务)详解
http://blog.csdn.net/ryantang03/article/details/7770939 Android中Service(服务)详解 标签: serviceandroidappl ...
- Android中Service的使用详解和注意点(LocalService)
Android中Service的使用详解和注意点(LocalService) 原文地址 开始,先稍稍讲一点android中Service的概念和用途吧~ Service分为本地服务(LocalServ ...
- Android中Service的一个Demo例子
Android中Service的一个Demo例子 Service组件是Android系统重要的一部分,网上看了代码,很简单,但要想熟练使用还是需要Coding. 本文,主要贴代码,不对Servic ...
- Android中Service和Activity之间的通信
启动Service并传递数据进去: Android中通过Intent来启动服务会传递一个Intent过去. 可以在Intent中通过putExtra()携带数据 Intent startIntent ...
- Android中Service 使用详解(LocalService + RemoteService)
Service 简介: Service分为本地服务(LocalService)和远程服务(RemoteService): 1.本地服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外L ...
- Android中Service的使用
我个人的理解是:我们平时使用的android系统的app的后台应用,就是这个原理 可以利用Service实现程序在后台运行,依照这个原理,可以通过Service来实现关键代码的运行与实现. <一 ...
- (六)Android中Service通信
一.启动Service并传递参数 传递参数时只需在startService启动的Intent中传入数据便可,接收参数时可在onStartCommand函数中通过读取第一个参数Intent的内容来实现 ...
- android中service启动后台程序
Service是Android中一个类,它是Android四大组件之一,使用Service可以在后台执行长时间的操作( perform long-running operations in the b ...
- Android中Service与多个Activity通信
由于项目需要,我们有时候需要在service中处理耗时操作,然后将结果发送给activity以更新状态.通常情况下,我们只需要在一个service与一个activity之间通信,通常这种情况下,我们使 ...
随机推荐
- information_schema系列四(跟踪,列约束,表和列)
这个系列的文章主要是为了能够让自己了解MySQL5.7的一些系统表,统一做一下备注和使用,也希望分享出来让大家能够有一点点的受益. 1:KEY_COLUMN_USAGE 按照官方的解释,这个表描述的是 ...
- android 多线程 示例
public class MyRun implements Runnable { int count = 1000; @Override public void run() { while (true ...
- SQL 中 SELECT 语句的执行顺序
好像自已在书写 SQL 语句时由于不清楚各个关键字的执行顺序, 往往组织的 SQL 语句缺少很好的逻辑, 凭感觉 "拼凑" ( 不好意思, 如果您的 SQL 语句也经常 " ...
- div层叠顺序额
在模态窗体中打开新div,结果该div不显示 该div不是没有显示,而是显示了,但是被这个模态状体挡住了 解决方法:修改z-index这个参数 该参数越大则显示在越上层,即可见
- device tree 生成device node 到 platform_device
http://blog.csdn.net/lichengtongxiazai/article/details/38942033 http://blog.csdn.net/mcgrady_tracy/a ...
- Selenium简单介绍
WEB自动化测试:指WEB应用系统从用户界面层面进行的自动化测试.通过用户界面测试内部的业务逻辑. 自身特点:(一)WEB页面上出现的元素有可能具有不确定性: (二)不同操作系统上不同WEB浏览器之间 ...
- GRUB密码设置
通过编辑GRUB启动参数可以轻松的进入单用户模式从而修改root密码,GRUB的密码设置可分为全局密码和菜单密码. 一,全局密码设置 在splashimage这个参数的下一行可以加上passw ...
- 关于ajax提交表单参数序列化和时间戳转换
ajax提交form表单, 序列化表单的参数 //var a = $("#addfm").serialize(); //将表单的内容序列化成为一个字符串 var a = $(&qu ...
- ABAP 根据操作员分组发送邮件
1,获取操作员姓名 SELECT SINGLE ADRP~NAME_TEXT INTO GS_OUTPUT-UNAMT FROM ADRP INNER JOIN USR21 ON ADRP~PERSN ...
- 怎样把windows中安装的程序列出来?
症状/问题我怎样把windows中安装的程序信息输出到一个文本文件中?解决方法使用 windows 操作系统中的命令:wmic就可以做到.下面的命令就可以把系统中安装的程序都输出到文件ProgramL ...