深入理解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 ...
随机推荐
- SOLID设计原则
SOLID设计原则 Single Responsibility Principle单一职责原则 单一职责原则(SRP)表明一个类有且只有一个职责. 一个类就像容器一样,它能添加任意数量的属性.方法等. ...
- Spring中使用到的设计模式
1.工厂模式:Beanfactory和ApplicationContext 2.单例模式:bean的构建 3.代理模式:AOP 4.模板模式:jdbcTemplate,hibernateTemplat ...
- 安装percona-toolkit.rpm时候报错:perl(Time::HiRes) is needed by percona-toolkit-2.2.16-1.noarch
1.安装percona-toolkit.rpm时候报错: warning: percona-toolkit.rpm: Header V4 DSA/SHA1 Signature, key ID cd2e ...
- 【luoguP3701】「伪模板」主席树
description byx和诗乃酱都非常都非常喜欢种树.有一天,他们得到了两颗奇怪的树种,于是各自取了一颗回家种树,并约定几年后比一比谁种出来的树更加牛x. 很快,这棵树就开花结果了.byx和诗乃 ...
- php 简单的工程模式 实现加法操作
class A{ protected $Num1; protected $Num2; public $result; public function getNum1(){ return $this-& ...
- 牛客多校第三次B——线段树维护线性基交
写线性基交函数时调试了半天.. #include<bits/stdc++.h> using namespace std; #define ll long long #define maxn ...
- NX二次开发-查询信息窗口是否打开UF_UI_is_listing_window_open
#include <uf.h> #include <uf_ui.h> UF_initialize(); //打开信息窗口 UF_UI_open_listing_window() ...
- 使用Docker在服务器上部署Ubuntu,本地传文件到docker
使用Docker在服务器上部署Ubuntu,本地传文件到docker 作者:王佳乐 目录 安装Docker 安装Docker 全部安装流程: 登录服务器 ssh username@ip 检查是否已经安 ...
- Java-Class-@I:org.apache.ibatis.annotations.Mapper
ylbtech-Java-Class-@I:org.apache.ibatis.annotations.Mapper 1.返回顶部 2.返回顶部 1. package com.ylbtech.ed ...
- JavaScript学习总结(七)——ECMAScript6(ES6)
一.ECMAScript概要 ECMAScript是一种由Ecma国际(前身为欧洲计算机制造商协会,英文名称是European Computer Manufacturers Association)通 ...