Service

简介

Service是Android的四大组件之一,属于计算型组件,它的作用是提供需在后台长期运行的服务(比如复杂计算、音乐播放、下载等),特点是无用户界面、在后台运行、生命周期长

生命周期 常用方法

Service_第1张图片

在Service的生命周期里,常用的有:

  • 4个手动调用的方法
手动调用方法 作用
startService() 启动服务
stopService() 关闭服务
bindService 绑定服务
unbindService 解绑服务
  • 5个自动调用的方法
内部自动调用的方法 作用
onCreate() 创建服务
onStartCommand() 开始服务
onDestroy() 销毁服务
onBind() 绑定服务
onUnbind() 解绑服务

类型

Service可以按照运行地点、运行类型、功能进行分类,具体如下:

具体分类

Service_第2张图片

详细介绍

Service_第3张图片

使用详解

本地Service

这是最普通、最常用的后台服务Service

使用步骤

  • 步骤1:新建子类继承Service类

    需要重写父类的onCreate()、onStartCommand()、onDestroy()和onBind()方法

  • 步骤2:构建用于启动Service的Intent对象

  • 步骤3:调用startService()启动Service、调用stopService()停止服务

  • 步骤4:在AndroidManifest.xml里注册Service

AndroidManifest里Service的常见属性说明:

属性 说明 备注
android:name Service的类名
android:label Service的名字 若不设置,默认为Service类名
android:icon Service的图标
android:permission 申明此Service的权限 有提供了该权限的应用才能控制或连接此服务
android:process 表示该服务是否在另一个进程中运行(远程服务) 不设置默认为本地服务;remote则设置成远程服务
android:enabled 系统默认启动 true:Service将会默认被系统启动;不设置则默认为false
android:exported 该服务是否能够被其他应用程序所控制或连接 不设置默认此项为false

可通信的服务Service

这种Service增加了与Activity通信的功能,即使用绑定Service服务(Binder类、bindService()、onBind()、unbindService()、onUnbind())

前台Service

前台Service和后台Service(普通)最大的区别就在于:

  • 前台Service在下拉通知栏有显示通知,但是后台Service没有
  • 前台Service优先级较高,不会由于系统内存不足而被回收;后台Service优先级较低,当系统出现内存不足情况时,很有可能会被回收

远程服务Service

多个应用程序共享同一个后台服务(远程服务)

即一个远程Service与多个应用程序的组件(四大组件)进行跨进程通信
Service_第4张图片

具体使用

  • 为了让远程Service与多个应用程序的组件(四大组件)进行跨进程通信(IPC),需要使用AIDL

1.IPC:Intent-Process Communication,即跨进程通信
2.AIDL:Android Interface Definition Language,即Android接口定义语言;用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能

  • 在多进程通信中,存在两个进程角色:服务器端、客户端

  • 服务器端:
    步骤1:新建定义AIDL文件,并声明该服务需要向客户端提供的接口
    步骤2:在Service子类中实现AIDL中定义的接口方法,并定义生命周期的方法(onCreate、onBind)
    步骤3:在AndroidManifest.xml中注册服务,声明为远程服务

  • 客户端:
    步骤1:拷贝服务端的AIDL文件到目录下
    步骤2:使用Stub.asInterface接口获取服务器的Binder,根据需要调用服务提供的接口方法
    步骤3:通过Intent指定服务端的服务名称和所在包,绑定远程Service

使用场景

Service_第5张图片

其他思考

Service与Thread的区别

  • 结论:Service与Thread没有任何关系
  • 之所以有人会将他们联系起来,主要是因为Service的后台概念

后台:后台任务运行完全不依赖UI,即使Activity被销毁/程序被关闭,只要进程还在,后台任务就可以继续运行

  • 关于二者的异同,具体如下图:
    Service_第6张图片
  • 注:一般会将Service和Thread联合着用,即在Service中再创建一个子线程(工作线程)去处理耗时逻辑,如下图:
@Override  
public int onStartCommand(Intent intent, int flags, int startId) {  
//新建工作线程
    new Thread(new Runnable() {  
        @Override  
        public void run() {  
            // 开始执行后台任务  
        }  
    }).start();  
    return super.onStartCommand(intent, flags, startId);  
}  
  
class MyBinder extends Binder {  
    public void service_connect_Activity() {  
  //新建工作线程
        new Thread(new Runnable() {  
            @Override  
            public void run() {  
                // 执行具体的下载任务  
            }  
        }).start();  
    }  
  
}  

Service和IntentService的区别

多线程的应用在Android开发中是非常常见的,常用方法只要有:

  • 继承Thread类
  • 实现Runnable接口
  • AsyncTask
  • Handler
  • HandlerThread
  • IntentService

定义

IntentService是Android里的一个封装类,继承自四大组件之一的Service,它的作用是处理异步请求、实现多线程

使用场景

线程任务需要按顺序、在后台执行

1.最常见的场景:离线下载
2.不符合多个数据同时请求的场景:所有的任务都在同一个Thread looper里执行

工作原理

IntentService的工作原理、源码工作流程如下:
Service_第7张图片

特别注意

若启动IntentService多次,那么每个耗时操作都以队列的方式在IntentService的onHandleIntent回调方法中依次执行,执行完自动结束

IntentService如何单独开启一个新的工作线程?

@Override
public void onCreate() {
    super.onCreate();
    
    // 1. 通过实例化andlerThread新建线程 & 启动;故 使用IntentService时,不需额外新建线程
    // HandlerThread继承自Thread,内部封装了 Looper
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();
  
    // 2. 获得工作线程的 Looper & 维护自己的工作队列
    mServiceLooper = thread.getLooper();

    // 3. 新建mServiceHandler & 绑定上述获得Looper
    // 新建的Handler 属于工作线程 ->>分析1
    mServiceHandler = new ServiceHandler(mServiceLooper); 
}


   /** 
     * 分析1:ServiceHandler源码分析
     **/ 
     private final class ServiceHandler extends Handler {

         // 构造函数
         public ServiceHandler(Looper looper) {
         super(looper);
       }

        // IntentService的handleMessage()把接收的消息交给onHandleIntent()处理
        @Override
         public void handleMessage(Message msg) {
  
          // onHandleIntent 方法在工作线程中执行
          // onHandleIntent() = 抽象方法,使用时需重写 ->>分析2
          onHandleIntent((Intent)msg.obj);
          // 执行完调用 stopSelf() 结束服务
          stopSelf(msg.arg1);

    }
}

   /** 
     * 分析2: onHandleIntent()源码分析
     * onHandleIntent() = 抽象方法,使用时需重写
     **/ 
      @WorkerThread
      protected abstract void onHandleIntent(Intent intent);

IntentService如何通过onStartCommand()将Intent传递给服务并依次插入到工作队列中


/** 
  * onStartCommand()源码分析
  * onHandleIntent() = 抽象方法,使用时需重写
  **/ 
  public int onStartCommand(Intent intent, int flags, int startId) {

    // 调用onStart()->>分析1
    onStart(intent, startId);
    return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

/** 
  * 分析1:onStart(intent, startId)
  **/ 
  public void onStart(Intent intent, int startId) {

    // 1. 获得ServiceHandler消息的引用
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;

    // 2. 把 Intent参数 包装到 message 的 obj 发送消息中,
    //这里的Intent  = 启动服务时startService(Intent) 里传入的 Intent
    msg.obj = intent;

    // 3. 发送消息,即 添加到消息队列里
    mServiceHandler.sendMessage(msg);
}

源码总结

总上面的源码可以看出:IntentService本质上是Handler + HandlerThread

  1. 通过HandlerThread单独开启1个工作线程:IntentService
  2. 创建1个内部Handler:ServiceHandler
  3. 绑定ServiceHandler与IntentService
  4. 通过onStartCommand()传递服务Intent到ServiceHandler,依次插入Intent到工作队列中并逐个发送到onHandlerIntent()
  5. 通过onHandlerIntent()依次处理所有Intent对象所对应的任务

因此我们通过复写onHandlerIntent()、在里面根据Intent的不同进行不同的线程操作即可

注意事项

1.工作任务队列是顺序执行的
2.不建议通过bindService()启动IntentService

注意事项1

即若一个任务正在IntentService中执行,此时你再发送1个新的任务请求,这个新的任务会一直等待直到前面一个任务执行完毕后才开始执行

原因:

  • 由于onCreate()只会调用一次,也就是说只会创建1个工作线程
  • 当多次调用startService(Intent)时(即onStartCommand(也会调用多次)),其实不会创建新的工作线程,只是把消息加入到消息队列中并等待执行
  • 所以多次启动IntentService会按顺序执行事件
  • 若服务停止,则会清除消息队列汇总的消息,后续的事件不执行

注意事项2

原因:

// 在IntentService中,onBind()`默认返回null
@Override
public IBinder onBind(Intent intent) {
    return null;
}

采用bindService()启动IntentService的生命周期如下:

onCreate() -> onBind() -> onUnbind() -> onDestory()

即并不会调用onStart()或onStartCommand(),故不会将消息发送到消息队列,那么onHandlerIntent()将不会回调,即无法实现多线程的操作

此时,就应该使用Service而不是IntentService

对比

与Service的区别

Service_第8张图片

与其他线程的区别

Service_第9张图片

你可能感兴趣的:(Android学习笔记)