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

推荐阅读更多精彩内容