深入理解Android-清晰的理解Service
1、什么是Service
2、Service的生命周期
3、Service的工作过程
4、Service的start和bind状态有什么区别?
5、同一个Service,先startService,然后再bindService,如何把它停止掉?
6、你有注意到Service的onStartCommand方法的返回值吗?不同返回值有什么区别?
7、Service的生命周期方法onCreate、onStart、onBind等运行在哪个线程?
1.什么是service?
服务是一种应用程序组件,表示应用程序希望在不与用户交互的情况下执行长时间运行的操作,或者为其他应用程序提供的功能。每个服务类必须在其包的AndroidManifest.xml中具有相应的<service>声明。服务可以使用Context.startService()和Context.bindService()来启动。 请注意,与其他应用程序对象一样,服务在主机进程的主线程中运行。这意味着,如果你的服务要做任何CPU密集型(如MP3播放)或阻塞(如网络)操作,它应该产生自己的线程来完成这项工作。有关这方面的更多信息可以在“进程和线程”中找到。 IntentService类可作为Service的标准实现提供,它具有自己的线程,用于调度要完成的工作。
2.Service 的生命周期
Service有两种启动方式:
调用Context.startService(),那么系统将检索服务(如果需要,创建它并调用它的onCreate()方法),然后使用客户端提供的参数调用它的onStartCommand(Intent,int,int)方法。此服务将继续运行,直到调用Context.stopService()或stopSelf()。请注意,对Context.startService()的多次调用不会嵌套(尽管它们会导致对onStartCommand())进行多次相应调用),因此无论启动多少次,服务都会停止一次Context.stopService()或stopSelf () ;然而,服务可以使用他们的stopSelf(int)方法来确保服务不会停止,直到处理完启动的意图为止。对于已启动的服务,根据从onStartCommand()返回的值,他们可以决定运行两个额外的主要操作模式:START_STICKY用于根据需要显式启动和停止的服务,而使用START_NOT_STICKY或START_REDELIVER_INTENT对于在处理发送给它们的任何命令时应该只保持运行的服务。
调用Context.bindService()来获得到服务的持久连接。如果服务尚未运行(同时调用onCreate()),则同样会创建服务,但不会调用onStartCommand()。客户端将收到服务从其onBind(Intent)方法返回的IBinder对象,从而允许客户端将该服务调用回该服务。只要建立连接(无论客户是否保留对服务的IBinder的引用),该服务就会继续运行。返回的IBinder通常是用于一个复杂的接口,已经被写入aidl。
服务既可以启动,也可以绑定连接。在这种情况下,只要系统启动,或者存在与Context.BIND_AUTO_CREATE标志的一个或多个连接,系统就会继续运行该服务。一旦这些情况都不成立,就会调用服务的onDestroy()方法,并且服务被有效终止。从onDestroy()返回后,所有清理(停止线程,取消注册接收者)应该完成。
3.Service的工作过程
Service分为两种工作状态:一种是启动状态,主要用于执行后台计算;另一种是绑定状态,主要用于其他组件和service的交互。service的两种状态是可以共存的,那么Service既可以处于启动状态也可以处于绑定状态。
启动状态:
Intent intent = new Intent(this, MyService.class);
startService(intent);
Intent intent = new Intent(this, MyService.class); bindService(intent,conn,BIND_AUTO_CREATE);
service的启动过程
1.startService(intent);
我们看一下 service的源码 :package android.app.Service;
public abstract class Service extends ContextWrapper implements ComponentCallbacks2
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
通过mBase,调用startService
public class ContextWrapper extends Context {
Context mBase; public ContextWrapper(Context base) {
mBase = base;
}
而Context类是个abstract
public abstract class Context
startService 是通过Context调用的,那我们看下ContextImpl 是如何实现startService 的。
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
} private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
// 开启服务 ActivityManagerNative.getDefault() 其实就是 ActivityManagerService(AMS)
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
"Not allowed to start service " + service
+ " without permission " + cn.getClassName());
} else if (cn.getPackageName().equals("!!")) {
throw new SecurityException(
"Unable to start service " + service
+ ": " + cn.getClassName());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
简单说一下 ActivityManagerNative
public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
/**
* Cast a Binder object into an activity manager interface, generating
* a proxy if needed.
*/
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
} return new ActivityManagerProxy(obj);
} /**
* Retrieve the system's default/global activity manager.
*/
static public IActivityManager getDefault() {
return gDefault.get();
}
} private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
public final class ActivityManagerService extends ActivityManagerNative
ActivityManagerService 是继承ActivityManagerNative的 AMS启动服务是一个远程调用过程,更具体的实现过程大家可以看源码,这里就不在长篇幅的写源码的启动过程了。
2.bindService 的绑定过程同样在ContextImpl 中,大家可自行翻阅理解。
4.Service的start和bind状态有什么区别?
start启动的service,不依赖组件,有独立的生命周期,多次调用service不会嵌套,尽管会对onStartCommand()多次调用,因此无论启动多少次,服务都会停止一次Context.stopService()或stopSelf ()(IntentService会自动调用一次onStopSelf).然而,服务可以使用他们的stopSelf(int)方法来确保服务不会停止,直到处理完启动的意图为止。对于已启动的服务,根据从onStartCommand()返回的值,他们可以决定运行两个额外的主要操作模式:START_STICKY用于根据需要显式启动和停止的服务,而使用START_NOT_STICKY或START_REDELIVER_INTENT对于在处理发送给它们的任何命令时应该只保持运行的服务。
bind绑定的service依赖于组件,组件销毁service也随之销毁,需要注意的比如在Activity中bind了service,那么必须在onDestory方法中销毁service调用unBindServie方法。多次调用bind方法只会调用一次onBind()方法,但不会调用onStartCommand()。停止服务是调用了n次bindService,就必须要调用n次unBindService.
5.同一个Service,先startService,然后再bindService,如何把它停止掉?
startService 不论调用几次,只需要stopService(或stopSelf) 一次即可停止掉服务。
如果调用了n次bindService,必须调用n次unBindService 方法,才能停止掉服务。
执行的顺序没有要求。
最后一个stopService(或stopSelf)或者unBindService方法会导致Service的onDestroy方法执行。
6. Service的onStartCommand方法的返回值?不同返回值有什么区别?
一共有四种返回值
START_STICKY_COMPATIBILITY,
START_STICKY,
START_NOT_STICKY,
START_REDELIVER_INTENT,
/**
*不保证的{@link #START_STICKY}版本
* {@link #onStartCommand}在被杀后会再次被调用。
*为了兼容版本,在service被杀死后,并不保证onStartCommand 会被再次调用
*/
public static final int START_STICKY_COMPATIBILITY = 0; /**
* 如果此service是进程在启动时被杀死(返回后),保持启动状态,但不保留Intent ,之后系统会尝试重启该service,并重新回调
* onStartCommand方法,如果没有其他的start命令,会传递给service 的intent为null,需要注意onStartCommand方法对intent的非空判断
*/
public static final int START_STICKY = 1; /**
* 常规操作,除非死之前还有组件调用startService,否则系统不会保留启动状态并重启该service
*/
public static final int START_NOT_STICKY = 2; /**
* service 被杀死后,系统会组织一次service重启(除非之前调用了stopSelf)被杀死之前最后一次传递的intent将被执行,该flag将不会传递空intent,
*这适用于那些应该立即恢复正在执行的工作的服务,如下载文件。
*/
public static final int START_REDELIVER_INTENT = 3;
7.Service的生命周期方法onCreate、onStart、onBind等运行在哪个线程?
Service 默认是运行在主线程的,并且其生命周期也是运行在主线程的,所以要想在service中执行耗时操作必须另起一个Thread线程(或者使用IntentService),否则会ANR.
作者:JakePrim
链接:https://www.jianshu.com/p/087415add7a5
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
深入理解Android-清晰的理解Service的更多相关文章
- [转载] 深入理解Android之Java虚拟机Dalvik
本文转载自: http://blog.csdn.net/innost/article/details/50377905 一.背景 这个选题很大,但并不是一开始就有这么高大上的追求.最初之时,只是源于对 ...
- [深入理解Android卷一全文-第三章]深入理解init
因为<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该因为纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的全部内容. ...
- 《深入理解Android 卷III》第四章 深入理解WindowManagerService
<深入理解Android 卷III>即将公布,作者是张大伟.此书填补了深入理解Android Framework卷中的一个主要空白.即Android Framework中和UI相关的部分. ...
- [深入理解Android卷一全文-第十章]深入理解MediaScanner
由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该由于纸质媒介的问题而中断.所以我将在CSDN博客中全文转发这两本书的全部内容. ...
- 《深入理解Android 卷III》第六章 深入理解控件(ViewRoot)系统
<深入理解Android 卷III>即将公布,作者是张大伟.此书填补了深入理解Android Framework卷中的一个主要空白,即Android Framework中和UI相关的部分. ...
- (转载)你真的理解Android AIDL中的in,out,inout么?
前言 这其实是一个很小的知识点,大部分人在使用AIDL的过程中也基本没有因为这个出现过错误,正因为它小,所以在大部分的网上关于AIDL的文章中,它都被忽视了——或者并没有,但所占篇幅甚小,且基本上都是 ...
- 安卓学习资料推荐《深入理解Android:卷2》下载
下载地址:百度云下载地址 编辑推荐 <深入理解Android:卷2>编辑推荐:经典畅销书<深入理解Android:卷I>姊妹篇,51CTO移动开发频道和开源中国社区一致鼎力推荐 ...
- 深入理解 Android 之 View 的绘制流程
概述 本篇文章会从源码(基于Android 6.0)角度分析Android中View的绘制流程,侧重于对整体流程的分析,对一些难以理解的点加以重点阐述,目的是把View绘制的整个流程把握好,而对于特定 ...
- [译]:Xamarin.Android开发入门——Hello,Android Multiscreen深入理解
原文链接:Hello, Android Multiscreen_DeepDive. 译文链接:Xamarin.Android开发入门--Hello,Android Multiscreen深入理解. 本 ...
- Android动画的理解
基础知识 在我们开始讲Android动画这个知识点之前,我们了解下相应的基础知识点. Shape篇 一般用Shape定义的XML文件是存放在Drawable目录下,广泛应用于在Button.TextV ...
随机推荐
- SpringCloud+Eureka+Feign+Ribbon+zuul的简化搭建流程和CRUD练习
环境:win10--idea2019--jdk8 1.搭建Eureka服务模块 1.1 新建eureka服务模块(Sping Initializr) 取名为eureka-server,并添加如下Dep ...
- notepad++去换行(简单、快捷)
文本处理问题 这个方式可以快捷处理, 不用Linux命令, linux 与window之间的文件转换很烦人, 这个方法可以处理
- $.extend() $.fn.extend()
(非原创)jQuery为开发插件提拱了两个方法,分别是:jQuery.fn.extend();jQuery.extend();虽然 javascript 没有明确的类的概念,但是用类来理解它,会更方便 ...
- Python获取房价信息和导出EXCEL
房价与生活息息相关,那么各地区房价情况和差别咋样呢? 可以打开网站或手机APP去查询一下,不过查看到的数据有限,很不过瘾~ 作为一个合格的程序员,要懂得用代码解决问题! 第一步:打开一个房产交易平台 ...
- 在fedora下面安装ftp服务器
Fedora版本:Fedora 12 1. 安装vsftp #yum install vsftpd 一路yes,最后提示安装成功. 2. 配置vsftpd.conf. #vi /etc/vsftpd/ ...
- VS2010-MFC(Ribbon界面开发:为Ribbon Bar添加控件)
转自:http://www.jizhuomi.com/software/253.html 前面一节为大家简单介绍了如何创建Ribbon样式的应用程序框架,本节教程就来初步讲讲怎样为Ribbon Bar ...
- 最详尽使用指南:超快上手Jupyter Notebook
最详尽使用指南:超快上手Jupyter Notebook - CSDN博客https://blog.csdn.net/DataCastle/article/details/78890469
- ElasticSearch 命令执行漏洞(CVE-2014-3120)
POST /_search?pretty HTTP/1.1 Host: your-ip:9200 Accept: */* Accept-Language: en User-Agent: Mozilla ...
- nodejs--express安装失败的原因
1.检查更新所有的npm ,jade,或者ejs. 2.在用jade或ejs也是有区别的,jade适合个人秀,ejs更实用与商务. 3.express在4.+之后的版本都分离了,推荐用3.+的版本稳定 ...
- JAVA发展历史!
前言 自1946年2月14日世界上首款计算机问世,第一代计算机语言“机器语言”便诞生了,它使用的是最原始的穿孔卡片,这种卡片上使用的语言只有专家才能理解,与人类语言差别极大.这种语言本质上是计算机能识 ...