Handler与HandlerThread、IntentService源码解析

在前面的博客当中为大家分析过了Handler的源码,今天这篇博客的主要内容是为大家结合HandlerThread讲述一下Handler的另外一种比较酷炫的用法,以及这种酷炫的用法又是如何结合Service创造出IntentService这么酷的类的。

首先为大家总结一下前面Handler几个关键的核心知识点:
1、Handler是通过Handler的实例化对象进行线程间的切换的
2、Handler必须在主线程中创建,因为不在主线程中创建的Handler没有Loop,在Handler源码中设置就会报错。没有Loop就无法进行Handler最主要的消息机制
3、Handler消息的解释是通过Loop.loop()方法中通过Handler的实例化对象(msg.target)回调去实现Runnable接口中的内容
4、不同的线程都有不同的Looper和相应的消息队列(MessageQueue),都存储在一个叫ThreadLocal的类当中

这些特性就解释了Handler应用的一些表面现象:
1、即使在不同的线程中只要是同一个Handler对象都能接收到同一个Handler对象所发的消息,因为消息的回调是通过Handler的实例化对象
2、即使在不同的界面,同样也能接收到消息,只要在同一个线程中就可以了,因为同一个线程用的是同一个消息队列所以能够收到消息。

复习完了Handler的知识点,下面给大家看一段酷炫的Handler的用法,代码如下:

HandlerThread handlerThread = new HandlerThread("HandlerThread");
        Handler handler = new Handler(handlerThread.getLooper());
        handler.post(new Runnable() {

            @Override
            public void run() {

                Thread thread = Thread.currentThread();
                System.out.println("threadIdRunnable = " + thread.getId());
            }
        });
    }

这里给大家的思考就是Handler中的Runnbale接口执行的时候,里面的代码是在主线程执行的么?

答案当然是否定的,这段代码的执行时在HandlerThread子线程当中执行的,利用了消息队列的特性,即使Handler.post(new Runable())方法使用很多次,使消息队列中有很多消息,也不会产生线程不安全的问题,因为这是个消息队列,只会等一个消息执行完了再执行下一个消息,Handler的这种用法即避免了在主线程执行耗时操作,又避免了线程不安全的问题,是不是很酷。

那么就大家来分析一下能够产生这种效果的原因:

大家在前面应该看到了HandlerThread这个类,先给大家看一下HandlerThread这个类的源代码:

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    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.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
      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;
    }
    }

大家仔细看HandlerThread 这个类继承自Thread,和普通Thread唯一不同的地方就是在于这个类用于自己的Loop.
这下明白了,如果一个Handler使用了HandlerThread中的Loop,那么在当执行Hanndler中Runnable接口中的内容的时候。必须先执行Loop.loop()这个方法才能在当中利用Handler的实例化对象回调Runable接口中的内容。但是Loop.loop()这个方法由于Loop是HandlerThread的,所以Loop.loop()这个方法的调用必须是在HandlerThread中,这就解释了为什么说这个操作是在子线程当中。OK,为大家讲述完了Hanlder结合HandlerThread的酷炫用法.
下面为大家讲述IntentService,IntentService实际上是一个继承自Service的类,首先为大家先来复习一下关于Service的生命周期。主要讲述常用的几个生命周期,用StartService的方式启动服务
onCreate() 第一次启动服务的时候会回调这个方法
onStartCommand() 后面每次启动都会回调这个方法
onDestroy() 服务销毁的时候会启动这个方法

那么大家来看看在IntentService的onCreate()这个方法里面做了什么样的操作呢?

@Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

小伙伴们是不是惊呆了,没错,这个其实就是我上面为大家讲述的关于Handler的炫酷用法,在一个Handler了里面指定了一个HandlerThread的Loop,这样后面Hanlder方法里面的操作就在子线程里面了,还不会出现因为多线程带来的线程不安全的问题,因为Handler的处理机制是一个消息队列。

那在Service的生命周期onStartCommond里面做了什么呢,
大家情况源码:

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

回调了onStart()里面的内容,情况onStart()里面的代码:

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

onStart里面的操作竟然就是把intent和startId当做消息用Handler发了出去,大家请看消息的接收代码:

private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

大家情况在handleMessage,其实就是接收了消息,然后调用了onHandleIntent()这个方法,所以这也是为何我们使用IntentService的时候要重写这个方法,IntentServcie的精华就在于利用了Service这个组件在后台运行的特性,并且利用了Handler使用子线程的Looper的话,那么Handler里面的操作就是在子线程里面,并且利用Handler的消息队列机制避免了线程的不安全性。接着调用了stopSelf()方法把自己这个服务干掉了,并且看onDestroy()方法:

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

将这个消息队列的停止了,大家在这个过程中注意这一点避免内存泄露。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值