Android四大组件之Service

Service 用于在后台完成用户指定的操作,它可以用于播放音乐,文件下载和检查新消息推送等。用户可以使用其他组件来与Service通信。本篇文章将介绍Service的实现和使用方式:

  • Service的概念与分类
  • Service的生命周期的管理
  • Service的基本用法
  • Bound Service
  • IntentService

一 Service的概念与分类

概念:
Service(服务) 是能够在后台长时间运行,并且不提供用户界面的应用程序组件。其他应用程序组件能启动 Service,并且即便用户切换到另一个应用程序,Service还可以在后台运行。此外,组件能够绑定到Service并与之交互,甚至执行进程间通信(IPC)。例如 Service能在后台处理网络事务、播放音乐、执行文件操作或者与 Content Provider通信等。

分类:
Service按照启动方式可以分为以下两种类型:

  • Started Service: 当应用程序组件(如Activity)通过调用startService()方法启动Service时,Service处于启动状态。一旦启动,Service能在后台无限期运行。
  • Bound Service: 当应用程序组件通过调用bindService()方法绑定到Service时,Service处于绑定状态。多个组件可以一次绑定到一个Service上,当他们都接触绑定时,Service被销毁

Started ServiceBound Service 的区别

Started Service Bound Service
使用 startService() 方法启动 调用bindService() 方法绑定
通常只启动,不返回值 发送启动,得到返回值
启动Service 的组件与Service之间没有关联,即使关闭该组件,Service 也会一直运行 启动Service的组件与Service 绑定在一起,如果关闭该组件,Service就会停止
回调onStartConmond() 方法,允许组件启动Service 回调OnBind() 方法,允许组件绑定Service

虽然本篇文章将两种类型的Service分开讲述,但是Service也可以同时属于两种类型,既可以启动(无限期启动),也能绑定。不管应用程序是否为启动状态、绑定状态,或者两者兼有,都能通过Intent使用Service。我们可以在配置文件中将Service生命为私有的,从而阻止其他应用程序访问。

二 Service的生命周期

Service的生命周期比Activity的简单的多,但是却需要我们更加关注
Service如何创建和销毁,因为Service可能在用户不知情的情况下在后台运行。即下图为Service的生命周期


Service的生命周期

Service的生命周期可以分为两个不同的路径:

  • 通过调用startService() 方法启动Service
    当其他组件调用startService()方法时,Service被创建,并且无限期运行,其自身必须调用stopSelf()方法或者其他组件调用stopService() 方法来停止Service,当Service停止时,系统将其销毁。
  • 通过bindService() 方法启动Service
    当其他组件调用bindService()方法方法时,Service被创建。接着客户端通过IBinder接口与Service通信。客户端通过unbindService() 方法关闭连接。多个客户端能绑定到同一个Service,并且当他们都解绑定时,系统销毁Service(Service不需要被停止)

这两条路径并非完全独立,我们可以绑定已经使用startService() 方法启动的Service。例如,后台音乐Service能使用包含音乐信息的Intent通过调用startService()方法启动。当用户需要控制播放器或者获得当前音乐信息时,可以调用bindService()方法绑定Activity到Service。此时,stopService()和 stopSelf() 方法全部被客户端解绑定时才能停止Service。
为了创建Service,开发人员需要创建Service类或其子类的子类。在实现类中,需要重写一下处理Service生命周期重要方面的回调方法,并根据需要提供组件绑定到Service的机制。需要重写的重要回调方法如下表:

方法名 描述
void onCreat() 当 Service 第一次创建的时候,系统调用改方法执行一次性建立过程(在系统调用onStartCommand() 或者 onBind() 方法前),如果 Service 已经运行,该方法不会被调用
void onStartCommand(Intent intent, int flags, int startId) 当其他组件(如Activity)调用startService() 方法请求 Service 启动时,系统调用该方法。一旦该方法执行,Service启动 并在后台无限期运行
IBinder onBind(Intent intent) 该方法是Service子类必须实现的方法,该方法返回一个IBinder对象,应用程序可以通过该对象与Service组件进行通信
void onDestory() 当 Service 不在使用并即将销毁的时,系统调用该方法
boollean onUnbind(Intent intent) 当Service绑定的所有客户端都断开链接时,系统调用该方法

三 Service的基本用法

应用程序组件能通过调用startService() 方法和传递 Intent对象来启动Service,在Intent对象中指定Service并且包含Service需要使用的全部数据。Service使用onStartCommand() 方法接受Intent。

Android 提供了两个类供开发人员继承以创建启动Service

  • Service: 这是所有Service的基类,当继承该类时,创建新线程执行Service的全部工作是非常重要的。因为Service默认使用应用程序主线程,这可能降低应用程序Activity的运行性能
  • IntentService: 这个是Service类的子类,它每次使用一个Worker线程来处理全部启动请求。在不必同时处理多个请求时,这个是最佳选择。我们仅需要实现onHandleIntent方法,该方法接受每次启动请求的Intent, 以便完成后台任务。

下边为Service的用法Demo:

public class MusicService extends Service {
  public MusicService() {
    }
    static boolean isplay; //定义当前播放状态
    MediaPlayer player;    //MediaPlayer对象
    
    @Override
    public IBinder onBind(Intent intent) {  //必须实现的绑定方法
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public void onCreate() {
        player = MediaPlayer.create(this, R.raw.music);   //创建MediaPlayer对像并加载播放的音乐文件
    }
   
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) { //实现音乐的播放
        if (!player.isPlaying()) {  //如果没有播放音乐
            player.start();  //播放音乐
            isplay = player.isPlaying();  //当前状态正在播放音乐
        }
        return super.onStartCommand(intent, flags, startId);
    }
    
    @Override
    public void onDestroy() {  //停止音乐的播放
        player.stop();   //停止音频的播放
        isplay = player.isPlaying();  //当前状态没有播放音乐
        player.release();  //释放资源
        super.onDestroy();
    }
  • onCreat() :在Service创建时调用
  • onStartCommand():在每次启动Service时调用
  • onDestory(): 在Service销毁时候调用

而且在创建Service之后,系统会自动在AndroidManifest.xml文件中配置Service。

<service 
        android:name=". MusicService"
        android:enabled="true"
        android:exported="true"/>
  • android:enabled: 用于指定Service 能否被实例化,true表示能,false表示不能,默认值是true,<application>标记也有自己的enable属性,适用于应用中所有的组件,当Service被启动后,只有 <application> 和 <service> 标记的enabled属性同时设置为true (两者的默认值都是true)才能让Service使用并能能被实例化。若任何一个为false Service将被禁用

  • android:exported: 用于指定其他应用程序组件能否调用Service或者与其交互

  • 启动Service
    我们可以从Activity或者其他应用程序组件通过传递Intent对象(指定要启动的Service到startService)方法启动Service,Android系统调用Service的onStartCommand() 方法,并将intent传递给他
    例如 Activity能使用显示Intent 和startService方法启动

Intent intent = new Intent(MainActivity.this, MusicService.class);
startService(intent);  //启动服务,从而实现播放背景音乐

在执行startService() 方法后,Android系统调用Service 的onStartCommand() 方法,如果Service还没有运行,系统首先调用onCreate() 方法,接着调用onStartCommand方法。

  • 停止 Service
    已启动的Service必须自己管理自己的生命周期,即系统不会不会停止或销毁Service,除非系统必须回收系统内存,而且在onStartCommand方法返回后Service继续运行,因此Service必须调用stopSelf() 方法停止自身,或者其他组件调用 stopService(), 停止后系统会尽快销毁Service

四 Bound Service

当应用程序组件调用bindService() 方法绑定 Service时,Service处于绑定状态。多个组件可以一次绑定一个Service上,当他们都解绑时,Service被销毁。
如果Service 仅用于本地应用程序并且不必跨进程工作,则开发人员可以实现自己的Binder类为客户端提供访问Service 公共方法的方式。
应用程序组件可以调用bindService() 方法绑定到Service:

/* *
 *  service: 通过Intent 指定要启动的Service
 *  conn:一个 ServiceConnection对象, 该对象用于监听访问者与Service之间的链接情况
 *  flags:指定绑定时是否自动创建Service,该值设置为0 时表示不自动创建,设置 BIND_AUTO_CREATE时表示 自动创建。
 * 
 * */
bindService(Intent service, ServiceConnection conn, int flags)

  • service: 通过Intent 指定要启动的Service
  • conn:一个 ServiceConnection对象, 该对象用于监听访问者与Service之间的链接情况
  • flags: 指定绑定时是否自动创建Service,该值设置为0 时表示不自动创建,设置 BIND_AUTO_CREATE时表示 自动创建。

注意: Activity、Service和ContentProvider 能绑定到Service,BroadcastReceiver不能绑定到Service

五 IntentService

IntentService是Service的子类,在介绍IntentService之前,先来了解使用Service时需要注意的两个问题,

  • Service 不会专门启动一个线程执行耗时操作,所有的操作都是在主线程中进行的,以至于容易出现ANR,所以需要手动开启一个子线程
  • Service 不会自动停止,需要调用stopSelf()方法 或者是stopService() 方法停止。

使用IntentService不会出现这两个问题,因为IntentService在开启Service时,会自动开启一个新的线程来执行它,另外,当Service运行结束后,会自动停止。

安卓相关文章阅读

Android四大组件之Service
Android四大组件之Activity

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

推荐阅读更多精彩内容