解析Service之你需要了解的一些东东
何为Service
Service,俗名服务。在Android系统中,Service与Activity就像一个妈生的,不仅长得像,而且行为(生命周期)也有一些类似。对于Activity来说大家肯定不会陌生,开发Android应用中打过交道最多的莫非就是Activity了,所以今天我们借助Activity来引入讲解Service。Service跟Activity一样是Android的四大组件之一,需要在AndroidManifest清单文件中进行注册。Service不像Activity在前台运行,而且是与之呼应进行后台运行的服务;如果把Activity当成下载软件的用户交互界面,而Service就是那个默默在后台运行的下载线程,所以Service的应用场景就是那些我们不需要它常驻前台但需要它一直在后台工作的时候,例如下载、播放音乐、IM软件监听客户端消息等。
Service的启动
启动Service有两种方式,不单调且奢华。在组件中我们可以用类似于Activity的启动方式的startService()来启动Service,用stopService()来关闭启动的服务;当然也可以用比较独特的绑定启动方式bindService()来启动Service这个服务,对应的解绑方法自然就是unbindService()。当然这两种启动方式的不同也意味着Service有着不一样的生命周期调用方法,我们先来看看Service启动的代码,详细如下:
定义一个Service类:
public class MyService extends Service {
//onBind为必须实现的抽象方法
@Override
public IBinder onBind(Intent arg0) {
return new MyBinder();
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onRebind(Intent intent) {
super.onRebind(intent);
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
/**
* 构造一个MyBinder类,其继承于Binder,而Binder实现了IBinder的接口
*/
public class MyBinder extends Binder{
//返回Service实例的引用
public MyService getId(){
return MyService.this;
}
}
}
启动方式为startService:
//启动一个Service
Intent intent = new Intent(this, MyService.class);
startService(intent);
//停止Service
stopService(intent);
startService()启动方式的生命周期为:
context.startService() -> onCreate() -> onStart() -> Service 运行中 -> context.stop() -> onDestroy() -> Service 被关闭
启动方式为bindService:
需要先构造一个实现ServiceConnection接口的一个连接类
private class MyServiceConnection implements ServiceConnection{
public MyServiceConnection(){}
@Override
public void onServiceConnected(ComponentName arg0, IBinder binder) {
MyService Myservice = ((MyService.MyBinder)binder).getService();
//绑定成功后调用
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
//当服务奔溃时调用
}
}
然后进行绑定启动Service
//绑定一个Service
Intent intent = new Intent(this, MyService.class);
MyServiceConnection conn = new MyServiceConnection();
bindService(intent, conn, Context.BIND_AUTO_CREATE);
//解绑Service
unbindService(conn);
当我们执行bindService()后,系统将会调用onCreate()和onBinde(),而在onBind()执行完毕后,将会回调ServiceConnection中的onServiceConnected()的方法,同时传回一个实现了IBinder接口的类(一般会选择传回继承至Binder的子类,因为Binder实现了IBinder的接口),然后我们可以通过某些手段(参考上面代码)从IBinder中获取Service的实例,一旦拿到了引用就相当于拿到了控制权,那时你要怎么玩弄Service还不是你自家儿的事情了。。。
bindService()启动方式生命周期:
context.bindService() -> onCreate() -> onBind() -> Service 运行中 -> context.unBindService() -> onUnbind() -> onDestroy() -> Service被关闭
以上两条生命周期非常正规的执行流程,但是哲学观告诉我们,有普遍就有特例,所以有一些奇葩的生命流程的存在也是可能的。
情形一:当我们在组件中调用startService()了来启动Service,但是我们并没有调用stopService()来销毁这个服务,那么我们在再次startService()来启动这个服务的时候,并没有调用onCreate()这个回调方法,而是仅仅执行了onStart()。为什么呢?因为在Android系统,每个服务都被设置成单例模式,无论调用多少次startService()来启动Service,在系统永远只会运行一个Service。而onCreate()是Service被创建时被调用的,所以在多次重复启动Service不会调用onCreate(),因为此时系统中已经存在Service这个服务了,所以只会调用onStart()。也就是说在多次启动服务时,onCreate()只会被调用一次,而onStart()可以被调用多次。
情形二:当我们需要把通过startService()启动的Service扫地出门的时候,调用stopService()就能满足我们小小的要求,这时候程序一般如我们预料的执行onDestroy()。但是如果我们并没有祭出stopService()这把宝剑,而是把调用者(如Activity)直接kill掉,那么会执行onDestroy()这个方法吗?答案是不会的,因为自从启动了Service后,该服务就跟调用者撇清关系了,不论调用者生老病死都跟他没半毛钱关系,除非打出stopService()通过意图(intent)把服务回收,当然这一切是建立在该Service是通过startService的方式启动的前提上。
情形三:现在说一下绑定服务(bindService)的情况,同startService的方式一样,如果多次重复启动Service,onCreate()依然只会调用创建Service服务的那个第一次。而对于onBind()则会在每次重复绑定服务的时候被调用,请示在这里onBind()最主要的作用就是将Ibinder传回到绑定者,借用其建立绑定者与Service的联系。而如果有多个绑定的存在,那么执行unbindService()仅仅只会触发onUnbind()而不会触发onDestroy(),只有最后一个绑定者调用unbindService()才会触发服务的onDestroy()的调用。还有一个特别的地方就是,如果销毁绑定者(例如Activity),那么绑定的这个Service会随他而去(执行onUnbid->onDestroy)。
关于Service的一些小知识小技巧
1、如果你需要一个在调用者退出后仍然不会被销毁,但同时需要获取他的引用,那么有这么一个小方法。先startService()启动服务,然后bindService绑定该服务,此时可以获取到Service的引用,然后在解绑unbindService,由于先startService所以只会执行onUnbind(),这时由于没有绑定关系,就算该调用者挂掉了,Service依然运行如旧。
2、Service虽然说是后台运行,但是实际上说它仍然是运行在主线程,这里说得运行在主线程是其onCreate、onStart、onBind等生命周期方法运行在主线程,如果这些方法进行诸如下载、读取大文件等耗时工作,会引起主线程的阻塞;所以我们一般会在Service中另起子线程运行我们需要的业务。
3、Service的启动、绑定和停止、解绑应该在对应的调用者相应的生命周期中,例如需要Service贯穿整个Activity,我们可以再onCreate中启动、绑定Service、在onDestroy中停止或解绑Service。如果只是需要在用户前台时运行服务,那么应该在onStart和onStop中进行相应的处理。不建议在onPause和onResume中对于服务进行启动停止的操作,因为这样会可能造成不必要的性能消耗,举个例子,当两个activity同时需要这个服务,那么在前个activity的onPause刚结束服务时,下个activity在onResume马上启动该服务,造成一些恶心的问题。
4、有人认为为什么在bindService的时候不把Ibinder返回到调用者那里,这个是因为启动服务时异步的,在调用bindService的时候是无法获取IBinder并返回的,所以只能在后面通过调用onbind的时候把IBinder扔到onServiceConnected的参数里面。
5、有些人会碰到onServiceConnected()在bindService后并没有被调用,请检查你的onBind()函数,如果返回值为null是不会触发onServiceConnected()的回调的,所以我们要确保onBind返回的是一个实现了IBinder接口的类。
6、我们可以在onUnbind()方法中返回true,这样的话,在我们解绑Service后再次绑定该Service,将会调用onRebind()这个不怎么常见的回调方法,而不会去执行onBind()。
写完睡觉,搞了一碗泡面,一股好恶心的感觉。。。。。
作者:enjoy风铃
出处:http://www.cnblogs.com/net168/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则下次不给你转载了。
解析Service之你需要了解的一些东东的更多相关文章
- k8s解析service地址方式
[root@k8s-master ~]# dig -t A kubernetes.default.svc.cluster.local. @10.96.0.10 ; <<>> D ...
- 解析BroadcastReceiver之你需要了解的一些东东
前些天把四大组件之一的Service扯了一遍,今天就要开始谈谈它的弟兄BroadcastReceiver了.写到这里我挺纠结的,因为广播接收者确实比较简单,但是各位就不要以为简单的就不内涵,也许我们慢 ...
- Service#onStartCommand返回值解析
Service#onStartCommand返回值解析 Service类有个生命周期方法叫onStartCommand,每次启动服务(startService)都会回调此方法.此方法的原型例如以下: ...
- mybatis结合分页的使用及解析.
首先说明: 这里分页是使用了SSM框架+ jsp 来做的, 当然分页还有其他的很多做法, 比如easyUI自带的分页效果. 但是这些原理都是很相似的, 再次只做为学习总结之用. 一, 效果图这里的截图 ...
- JSON解析实例——使用Json-lib
JSON解析实例——使用Json-lib Json-lib下载及使用 本文介绍用一个类库进行JSON解析. 工具下载地址:http://sourceforge.net/projects/json-li ...
- 深入解读Service Mesh背后的技术细节
在Kubernetes称为容器编排的标准之后,Service Mesh开始火了起来,但是很多文章讲概念的多,讲技术细节的少,所以专门写一篇文章,来解析Service Mesh背后的技术细节. 一.Se ...
- Android系统启动流程(一)解析init进程启动过程
整体流程大致如下: 1.init简介 init进程是Android系统中用户空间的第一个进程,作为第一个进程,它被赋予了很多极其重要的工作职责,比如创建zygote(孵化器)和属性服务等.in ...
- Android 属性系统 Property service 设定分析 (转载)
转自:http://blog.csdn.net/andyhuabing/article/details/7381879 Android 属性系统 Property service 设定分析 在Wind ...
- k8s service对象(三)
概述 service服务也是Kubernetes里核心字眼对象之一,Kubernetes里的每一个service其实就是我们经常提起的微服务架构中的一个微服务,之前讲解Pod,RC等资源对象其实都是为 ...
随机推荐
- 1071 Speech Patterns
People often have a preference among synonyms of the same word. For example, some may prefer "t ...
- 20145232 韩文浩 《Java程序设计》第2周学习总结
教材学习内容总结 这周主要学习了注释的使用,运算符的基本使用,认识了类型,变量与常量,以及一些语句语法.复习了进制转换. 整数 Short整数占用2字节,储存整数范围-32768 ~ 32767(2- ...
- _编程语言_C_C++_数据结构_struct
Struct 语句,访问成员使用 点结构. Example: #include <iostream> #include <cstring> using namespace st ...
- node-lessons
教程:https://github.com/alsotang/node-lessons 0 nvm 的全称是 Node Version Manager,之所以需要这个工具,是因为 Node.js 的各 ...
- js五道经典练习题--第三道实现购物车功能
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- spring中的两个数据库事务DataSourceTransactionManager 和 JtaTransactionManager区别
在spring与数据框架(mybatis或hibernate)容器的配置文件中通常会有 <!-- (事务管理)transaction manager, use JtaTransactionMan ...
- 必修3第三章概率mindmaps
% !Mode:: "TeX:UTF-8" \documentclass{article} \usepackage[screen]{geometry} \usepackage[no ...
- 合成的默认构造函数定义为delete的一种情况(针对C++11标准)
1. 默认初始化 如果定义变量时没有指定初值,则变量会被默认初始化,此时变量被赋予了"默认值". 对于类类型的变量来说,初始化都是依靠构造函数来完成的.因此,即使定义某个类的变量( ...
- 在线团队协作工具+在线UML工具
话不多说直接上https://worktile.com去看,顺便附上小众软件上面的介绍 默默增加worktile的外国原版https://trello.com/,worktile照着trello做的, ...
- jmeter 中 浮点数计算精度问题
jmeter 中 浮点数计算精度问题解决方法: 编写 beanshell 时使用 java.math.BigDecimal 方法构造,使用 BigDecimal 并且一定要用 String 来够造. ...