Android 学习之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类

public class MyService extends Service {

//onBind为必须实现的抽象方法

@Override

public IBinder onBind(Intent intent) {

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 =newIntent(this, MyService.class);

startService(intent);

//停止Service

stopService(intent);

startService()启动方式的生命周期为:

context.startService() -> onCreate() -> onStart() -> Service 运行中 -> context.stop() -> onDestroy() -> Service 被关闭

启动方式为bindService:

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) {

//当服务奔溃时调用

}

}

然后进行bind启动Service

//绑定一个Service

Intent intent =newIntent(this, MyService.class);

MyServiceConnection conn=newMyServiceConnection();

bindService(intent, conn, Context.BIND_AUTO_CREATE);

//解绑Service

unbindService(conn);

当我们执行bindService()后,系统将会调用onCreate()和onBind(),而在onBind()执行完毕后,将会回调ServiceConnection中的onServiceConnected()的方法,同时传回一个实现了IBinder接口的类(一般会选择传回继承至Binder的子类,因为Binder实现了IBinder的接口),然后我们可以通过某些手段(参考上面代码)从IBinder中获取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)。



写在最后


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()。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容