Android多线程之IntentService工作机制详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chenbaige/article/details/79590978

前言:IntentService在我们平常的开发过程中是非常常见的,我们都习惯于用它去处理一些耗时任务,但是对于它的内部机制,你真的了解?下面我们通过几个常见的面试题,来对IntentService一一剖析。想要了解更多关于Android多线程知识,请移步 Android多线程专栏

常见面试问题:

  • 你对IntentService了解么?说一下他的用处和原理?
  • IntentService和Service的区别?
  • 如何实现让IntentService任务可以并行执行?你会怎样去实现?

面对如上面试题目,你能够一一对答如流?接下来我们就围绕这三个题目,对IntentService做一个全方位的剖析。

IntentService的作用、优势和工作机制

  • IntentService的作用与优势:IntentService也是一种服务(Service)。其内部有一个特别的线程(HandlerThread),绑定一个Looper(维护一个消息队列),支持串形执行消息队列中的消息。同时,IntentService(服务)比普通的线程优先级更高,特别适用于处理高优先级的任务。最后,因为它有较高的优先级,因此服务不容易被杀死,可靠性较强。

  • IntentService工作机制

    第一步:自定义Intentservice服务:

public class MyIntentService extends IntentService {

    public MyIntentService() {
        super("MyIntentService");
    }

    //onCreate方法在主线程中执行
    @Override
    public void onCreate() {
        super.onCreate();
    }

//onStart方法在主线程中执行
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        super.onStart(intent, startId);
    }

//onHandleIntent方法在子线程中执行,用于串形处理耗时任务
    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        //处理耗时任务,通过测试可以发现,当有多个任务需要处理时,取出一个任务执行时,该方法会阻塞,直到这个任务处理完毕,才会取出下一个任务执行
    }

//onDestroy方法在主线程中执行
    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

第二步:开始服务

//通过下面的方式去启动服务
private void startService() {
        Intent intent = new Intent(MainActivity.this, MyIntentService.class);
        startService(intent);
    }

第三步:当我们启动服务后,会先回调用IntentService中的onCreate方法,进行一些初始化工作:

 @Override
    public void onCreate() {
        super.onCreate();
        //这就是处理耗时任务的工作线程,这里初始化并启动工作线程,用于处理任务
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
        //初始化ServiceHandler,并且与工作线程的Looper绑定在一起
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

看到这里,可能大家还是一脸懵逼。HandlerThread是个什么东东,ServiceHandler又是个什么鬼,在这里有什么用处??带着这些疑问,我们接着往下看:

  • 3.1:HandlerThread原理解析
//这就是HandlerThread的关键代码
public class HandlerThread extends Thread {
    //线程优先级
    int mPriority;
    int mTid = -1;
    //Looper对象,用于维护和轮询消息队列
    Looper mLooper;
    //Handler对象,用于发送和处理消息
    private @Nullable Handler mHandler;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

    protected void onLooperPrepared() {
    }
    //线程执行的关键代码,当启动线程后,就会进入下面的逻辑处理
    @Override
    public void run() {
        mTid = Process.myTid();
        //给当前线程创建Looper对象
        Looper.prepare();
        //同步获取Looper
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        //设置优先级
        Process.setThreadPriority(mPriority);
        //可以看到上面方法的定义,是空方法实现
        onLooperPrepared();
        //开启消息轮询,在前面讲过,loop方法最终会调用Handler的HandleMessage方法去处理轮询到的消息
        Looper.loop();
        mTid = -1;
    }
}

上面对HandlerThread类的分析已经很清晰了,当回调IntentService的onCreate方法的时候,创建一个HandlerThread对象,并且启动这个线程。一旦线程开始工作,就会维护一个消息队列,并且进入无限的消息轮询处理过程。可能有同学对上面讲到的Looper工作机制还是一头雾水,不用着急,请移步 Handler消息机制详解 查看Looper工作详情。想要了解更多关于Android多线程知识,请移步 Android多线程专栏

  • 3.2:ServiceHandler原理分析:
//这就是ServiceHandler类的完整定义
private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
        //在接收到消息的时候,调用onHandleIntent方法对消息进行处理,处理完所有消息后,停止服务
        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

看到这里,IntentService的onCreate方法逻辑就很清晰了。当Looper轮询到有新的消息时,就会通过Handler将消息发送出去,接下来Handler就会调用handleMessage方法处理消息。最终,handleMessage方法还是会调用我们自己实现的onHandleIntent方法去处理耗时任务。

第四步:在处理完onCreate方法后,立即进入IntentService的onStart方法,看一下onStart的内部逻辑:

//在这里我们才会收到开始服务时的Intent对象,并且创建一个新的Message对象,通过mServiceHandler发送出去
 @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

通过onStart方法可以看出,在这里我们才会拿到Intent对象,并创建Message对象通过mServiceHandler发送出去。因此,这时我们的消息队列才能轮询到新的消息,并且对消息进行处理。前面说到,当Looper轮询到新的消息后,就会调用handler的handleMessage方法去处理消息,handleMessage方法又会调用onHandleIntent方法。

第五步:调用onHandleIntent方法

    //工作在工作线程的抽象方法,因此我们定义IntengService时必须重写这个方法,用于处理耗时任务
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);

第六步:当处理完所有的任务后,IntentService会调用stopself方法停止服务,并且回调onDestroy方法

    @Override
    public void onDestroy() {
    //调用Looper的quit方法,内部其实是调用MessageQueue的quit方法,移除消息并停止消息的轮询
        mServiceLooper.quit();
    }

以上就是从创建IntentService服务到服务销毁的完整生命周期,回顾一下完整的调用链:

//自定义IntentService,,并且重写onHandleIntent方法
public class MyIntentService extends IntentService{} 
//开始服务
Intent intent = new Intent(MainActivity.this, MyIntentService.class);
startService(intent);
//回调onCreate方法(创建HandlerThread和ServiceHandler对象,绑定)
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
//回调onStart方法,发送消息
mServiceHandler.sendMessage(msg);
//HandlerThread中Looper轮询到消息队列有新消息,调用Handler的handleMessage方法处理消息
 public void handleMessage(Message msg) {
    onHandleIntent((Intent)msg.obj);
    stopSelf(msg.arg1);}
//调用我们重写的onHandleIntent方法处理耗时任务
protected abstract void onHandleIntent(@Nullable Intent intent);
//调用onDestory方法退出消息队列   
mServiceLooper.quit();
  • IntentService和service的区别
    这就是一个仁者见仁,智者见智的问题啦。在我看来,IntentService里面封装了Thread和Handler,我们可以很方便的实现多任务串形执行工作。如果通过Service去实现,我们需要自己去封装多线程、自己去实现消息队列的管理和轮询。相较来说IntentService更加方便,但Service扩展性更强。更多的细节,欢迎大家补充。
  • 通过IntentService实现任务并行处理
    前面说过,多任务到来时,都是首先通过onHandleIntent方法去处理的。因此,要实现多任务并行处理的话,可以在这个方法中实现线程池处理任务,当有任务到来时,不阻塞当前线程,直接交给线程池去处理。这样,相当于HandlerThread仅用于任务的管理与分配,并不参与执行,而真正处理耗时任务的是线程池。

    如果有同学有更好的实现方式,欢迎提出来,大家共同学习。ps:对线程池有不清楚的同学,可以移步:Android多线程之线程池Executor详解

总结:IntentService在我们我们的开发中应用是很广泛的,希望通过我的分享,能够使大家对它有更深的理解,并且学以致用。

猜你喜欢

转载自blog.csdn.net/chenbaige/article/details/79590978
今日推荐