Handler与HandlerThread、IntentService源码解析

来源:互联网 发布:王菲 蔡依林 知乎 编辑:程序博客网 时间:2024/06/11 04:15

在前面的博客当中为大家分析过了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();    }

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

1 0
原创粉丝点击