当前位置: 代码迷 >> 综合 >> IntentService 的使用与解析
  详细解决方案

IntentService 的使用与解析

热度:70   发布时间:2023-12-12 16:39:35.0

前言

IntentService 本质上也属于 Service,它可以说是一个使用起来更为简单的 Service。在我们基本的 Service 使用过程中,我们需要在 Service 中自己开启子线程进行耗时操作,并且在 Service 执行结束后还要调用 stopSelfstopService 方法来关闭 Service,而使用 IntentService 的话,这些问题将通通不需要关注。因为 IntentService 内部就是默认执行在子线程中的,并且在执行结束后它会帮我们自动停止 Service

在学习本章知识的时候,你需要先知晓以下知识点:

  1. Service的基本使用
  2. Android的异步消息处理机制

如果你对这两块知识点还不够熟悉的话,可以点击上面的超链接进行学习,那么接下来就让我们开始 IntentService 的学习吧,首先我们学习一下它的使用。

IntentService 的使用

IntentService 的使用和 Service 非常的相似,也比 Service 更加简单,我们接下来创建一个 MyIntentService 类,并继承自 IntentService。它的代码如下:

public class MyIntentService extends IntentService {
    private static final String TAG = MyIntentService.class.getSimpleName();public MyIntentService() {
    super("MyIntentService");}@Overridepublic void onCreate() {
    super.onCreate();Log.d(TAG,"onCreate");}@Overrideprotected void onHandleIntent(@Nullable Intent intent) {
    Log.d(TAG, "onHandleIntent's thread: " + Thread.currentThread());}@Overridepublic void onDestroy() {
    super.onDestroy();Log.d(TAG, "onDestroy");}}

我们对里面的 3 个生命周期中的方法进行重写,它们分别是 onCreateonHandleIntentonDestroy。如果你之前学习过 Service 的话,对 onCreateonDestroy 应当是相当熟悉的了,它们就是分别对应于 IntentService 启动时和停止时的方法。而 onHandleIntent 则比较陌生了,其实这个方法就是我们在 IntentService 中执行主要逻辑的方法,它默认是运行在子线程中的。这里我们对这 3 个方法只是简单地打印 Log,特别的我们会打印出 onHandleIntent 的线程,验证它是否真的运行在子线程中。

接下来我们就为 MainActivity 中添加一个按钮,通过按钮来调用 startService 方法来启动我们的 IntentService,代码如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private Button startServiceBtn;@Overrideprotected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);Log.d("MainActivity", Thread.currentThread().getName());setContentView(R.layout.activity_main);startServiceBtn = (Button)findViewById(R.id.start_service);startServiceBtn.setOnClickListener(this);}@Overridepublic void onClick(View v) {
    switch (v.getId()){
    case R.id.start_service:Intent startIntent = new Intent(this, MyIntentService.class);startService(startIntent);break;}}
}

这段代码逻辑相当简单,这里就不再做过多赘述了,我们在 ActivityonCreate 方法中也通过 Log 打印了线程的名字,运行程序,输出结果如下:

D/MainActivity: main
D/MyIntentService: onCreate
D/MyIntentService: onHandleIntent’s thread: Thread[IntentService[MyIntentService],5,main]
D/MyIntentService: onDestroy

可以看到,onHandleIntent 所处的线程与主线程名称不同,说明它确实是运行在子线程房中的。并且在运行完毕之后,运行了 onDestroy 方法,也证实 IntentService 在运行结束后确实会自动进行停止。

在通过例子验证了 IntentService 之后,我们接下来从源码的层面分析它是如何实现这些特性的。

源码分析

由于 IntentService 的源码量不算多,只有一百来行,所以这里我就直接将它都贴了过来逐步分析。它的源码如下:

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;private volatile ServiceHandler mServiceHandler;......@WorkerThreadprotected abstract void onHandleIntent(@Nullable Intent intent);
}

首先我们知道了这是一个继承自 Service 的抽象类,而它的抽象方法其实只有一个,就是 onHandleIntent 方法,它是我们实现具体逻辑的地方,就是需要我们自己去重写的。

接着我们看到它的成员 mServiceLoopermServiceHandler,它们分别是 Looper 类型和 ServiceHandler 类型的对象,而 ServiceHandler 又是继承自 Handler 的,看到这里我们应该非常熟悉了,它就是利用 Android 的异步消息处理机制来切换我们的线程的。

我们来看看 ServiceHandler 的实现代码:

private final class ServiceHandler extends Handler {
    public ServiceHandler(Looper looper) {
    super(looper);}@Overridepublic void handleMessage(Message msg) {
    onHandleIntent((Intent)msg.obj);stopSelf(msg.arg1);}
}

可以看到它的构造方法就是将一个 Looper 对象传给父类的构造方法进行 Handler 的初始化。

接着看到 handleMessage 方法,在这里会调用 onHandleIntent 方法,它就是在我们的自定义 IntentService 中被实现的嘛,然后在它执行完之后会调用 stopSelf 方法停止 Service,这也就是我们之前所说的 IntentService 在执行完之后会自动停止的原因了。那么我们只要找到了通过 mServiceHandler 发送消息的地方,我们就找到了关键的地方了。

接下来我们继续看到 onCreate 方法,它的代码如下:

@Override
public void onCreate() {
    super.onCreate();HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");thread.start();mServiceLooper = thread.getLooper();mServiceHandler = new ServiceHandler(mServiceLooper);
}

我们看到第 3 行,这里创建了一个 HandlerThread 对象 thread,我们来看看这个类的实现是什么样子的:

public class HandlerThread extends Thread {
    int mPriority;int mTid = -1;Looper mLooper;private @Nullable Handler mHandler;public HandlerThread(String name) {
    super(name);mPriority = Process.THREAD_PRIORITY_DEFAULT;}......
}

可以看到,它是继承自 Thread 的一个类,它内部同样也维护了两个重要的成员 mLoopermHandler。我们直接看到它的 run 方法:

@Override
public void run() {
    mTid = Process.myTid();Looper.prepare();synchronized (this) {
    mLooper = Looper.myLooper();notifyAll();}Process.setThreadPriority(mPriority);onLooperPrepared();Looper.loop();mTid = -1;
}

可以看到 run 方法中所做的工作其实就是通过 Looper.prepare 方法创建一个 Looper 对象,然后在同步块中通过 Looper.myLooper 赋值给 mLooper,紧接着在最后调用 Looper.loop 方法进入一个循环。

我们接着看到 getLooper 方法的实现:

public Looper getLooper() {
    if (!isAlive()) {
    return null;}// If the thread has been started, wait until the looper has been created.synchronized (this) {
    while (isAlive() && mLooper == null) {
    try {
    wait();} catch (InterruptedException e) {
    }}}return mLooper;
}

这个方法做的工作也很简单,首先判断该线程是否还存活,不存活的话直接返回 null,如果还存活的话,会在下面的同步块中判断 mLooper 对象是否已经创建,如果还未创建并且线程此时还存活的话,就会调用 wait 方法进入等待状态知道 mLooper 对象被创建为止,然后返回 mLooper

这里特别提到一点:既然有 wait 方法,那么肯定就要有 notifynotifyAll 方法。我们可以发现整个 HandlerThread 中只有在 run 方法中有一个 notifyAll 方法,它位于 mLooper = Looper.myLooper(); 这句代码之后。这么做的原因是我们的 Handler 一般是在 UI 线程中创建的(IntentService 同样也是这么做的),也就是说,我们必须等到 mLooper 创建完成,才能正确的返回 getLooperwaitnotifyAll 就是为了解决这两个线程的同步问题。

最后我们看到 HandlerThreadquit 方法:

public boolean quit() {
    Looper looper = getLooper();if (looper != null) {
    looper.quit();return true;}return false;
}

这个方法首先通过 getLooper 获取到 mLooper,如果不为空的话,就会执行 Looperquit 方法来终止 Looper,从而停止依赖于该 LooperHandler 的工作。

在分析完 HandlerThread 的代码之后,我们继续回到 IntentServiceonCreate 方法,为了方便观看这里我们就直接把它贴了过来:

@Override
public void onCreate() {
    super.onCreate();HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");thread.start();mServiceLooper = thread.getLooper();mServiceHandler = new ServiceHandler(mServiceLooper);
}

首先构造出一个 HandlerThread 对象,然后通过 start 方法开启了这个子线程,执行它的 run 方法,它的 run 方法我们前面分析过,会在这个子线程中创建一个 Looper 对象然后赋值给 HandlerThread 的成员 mLooper。紧接着 mServiceLooper 通过 HandlerThreadgetLooper 方法赋值,getLooper 其实就是返回 HandlerThreadmLooper 成员。最后 mServiceHandlermServiceLooper 作为参数传进它的构造方法中进行初始化,完成了对 mServiceHandler 的创建。

onCreate 这里我们也可以得出一个结论:mServiceHandlerhandleMessage 方法是在子线程中执行的,因为它依赖的 Looper 就是位于子线程中的嘛。

接下来我们看到 IntentServiceonStartCommand 方法,我们在前面的例子中说到过启动 IntentService 调用的就是 startService 方法,所以 onStartCommand 方法就会在 onCreate 方法后得到调用,它的实现如下:

public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
    onStart(intent, startId);return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

可以看到,它调用了 onStart 方法,并将 intentstartId 作为参数传了进去,我们接下来看看 onStart 方法做了什么:

@Override
public void onStart(@Nullable Intent intent, int startId) {
    Message msg = mServiceHandler.obtainMessage();msg.arg1 = startId;msg.obj = intent;mServiceHandler.sendMessage(msg);
}

可以很清楚地看到 onStart 方法做的就是通过调用 mServiceHandlersendMessage 方法发送消息了,然后就会调用 ServiceHandler 类中的 handleMessage 方法进行处理,在前面的分析中我们已经知道了 handleMessage 方法就是在子线程中调用 onHandleIntent 方法,这个方法是留待我们自己实现的,然后在执行完 onHandleIntent 方法之后就会调用 stopSelf 方法停止 Service,这个方法最终调用的也是 onDestroy 方法,我们看到 onDestroy 方法的实现:

@Override
public void onDestroy() {
    mServiceLooper.quit();
}

可以看到它就是调用 Looperquit 方法退出,然后使 mServiceHandler 的工作终止。

到这里,我们对 IntentService 的源码解析就结束了,我们对它进行一下总结:

  • IntentService 是继承自 Service 的一个类,它在内部维护了一个 Looper 类型的成员 mServiceLooperServiceHandler 类型的成员 mServiceHandler ,用于进行线程的切换。
  • IntentService 通过 startService 方法启动,所以它的生命周期应当是 onCreate - onStartCommand - onDestroy
  • onCreate 中进行了对 mServiceLoopermServiceHandler 的初始化,要注意到 mServiceLooper 是在子线程中运行的。
  • onStartCommand 中调用了 onStart 方法,该方法通过 mServiceHandler 发送消息给 ServiceHandlerhandleMessage 方法进行处理。
  • ServiceHandlerhandleMessage 方法调用了 onHandleIntent 方法和 stopSelf 方法,onHandleIntent 方法就是我们需要自己实现的方法,stopSelf 方法最终会调用到 onDestroy 方法,要注意到由于 mServiceLooper 是在子线程中运行的,所以 handleMessage 方法也是运行在子线程中的,同时它也实现了在 IntentService 运行完后自动停止 Service
  • onDestroy 中调用 Looperquit 方法退出 mServiceLooper,从而停止 mServiceHandler 的运行。

最后我们通过图形的形式来从另一个角度总结 IntentService
在这里插入图片描述
到这里,我们 IntentService 相关的知识点就介绍完了,IntentService 的源码还是比较少的,只要对基本的 Service 以及 Android 的异步消息处理机制够熟悉,理解它的实现还是比较容易的,希望大家能够通过这篇文章有所收获,有问题的话可以在下方评论区给我留言。