IntentService/HandlerThread/Handler源码阅读

首先是三个组件的源码解析

Handler消息源码流程分析
https://www.jianshu.com/p/6f25729ef62a

HandlerThread线程间通信 源码解析
https://www.jianshu.com/p/69c826c8a87d

IntentService源码解析
https://www.jianshu.com/p/83d9a3e09f0a

简单一点,
IntentService本质是一个Service(所以要清单注册)
在OnCreate阶段,初始化了一个HandlerThread(本质是一个Thread),一个ServiceHandler(本质是一个Handler),还附带了一个Intent。
通过HandlerThread创建的Looper*,把这个Looper绑定到ServiceHandler
此时就可以做到子线程处理Intent

在OnStart阶段,ServiceHandler把msg发送出去(其实就是那个Intent啦)
私有类ServiceHandler里的handleMessage方法处理这些intent。

IntentService的好处:在启动Service做操作后不用自己管理生命周期,在hanldeIntent之后就主动stopSelf。
而处理耗时操作又交给了HandlerThread这样的子线程。

那为什么不是交给Thread线程呢?
这里就得说 HandlerThread的好处,其自己在初始化的时候(实际是run方法)创建了一个Looper*,这个Looper是子线程的Looper。
把子线程Looper绑定到Handler上,这个Handler就成了子线程的Handler,专门用来处理类似联网的耗时操作(不可操作界面)

如果直接在Thread里new Handler,实际上是会报错的。
当然也有处理方案

new Thread() {
  public void run() {
    Looper.prepare();
    new Handler().post(runnable);//在子线程中直接去new 一个handler
    Looper.loop();//这种情况下,Runnable对象是运行在子线程
  }
}.start();

http://www.cnblogs.com/jingmo0319/p/5730963.html


梳理一下
handler
thread
threadLocal
looper
messageQueue
的对应关系

 private Looper looper;//其实是主线程的looper

private Handler handler1 = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            System.out.println("ceshi--handler1---" + msg.what + "---" + Thread.currentThread().getName());
        }
    };
    private Handler handler2 = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            System.out.println("ceshi---handler2---" + msg.what + "---" + Thread.currentThread().getName());
        }
    };

    Thread thread1 = new Thread() {
        @Override
        public void run() {
            super.run();
            Handler handler6 = new Handler(Looper.getMainLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    System.out.println("ceshi--handler6---" + msg.what + "---" + Thread.currentThread().getName());
                }
            };
            Message msg6 = new Message();
            msg6.what = 6;
            handler6.sendMessage(msg6);

            Message msg1 = new Message();
            msg1.what = 1;
            handler1.sendMessage(msg1);

            Message msg2 = new Message();
            msg2.what = 2;
            handler2.sendMessage(msg2);
            System.out.println("ceshi-thread1---" + Thread.currentThread().getName());
        }
    };

    Thread thread2 = new Thread() {
        @Override
        public void run() {
            super.run();
            Message msg3 = new Message();
            msg3.what = 3;
            handler1.sendMessage(msg3);

            Message msg4 = new Message();
            msg4.what = 4;
            handler2.sendMessage(msg4);

            System.out.println("ceshi-thread2---" + Thread.currentThread().getName());

             Looper.prepare();//这个才是子线程的looper
            Handler handler5 = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    System.out.println("ceshi--handler5--" + msg.what + "---" + Thread.currentThread().getName());
                }
            };
            Message msg5 = new Message();
            msg5.what = 5;
            handler5.sendMessage(msg5);
            Looper.loop();

        }
    };

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        looper = getMainLooper();
        System.out.println("ceshi---mainTh--"+Thread.currentThread().getName());
        

        thread1.start();
        thread2.start();
}

输出结果

System.out: ceshi---mainTh--main
System.out: ceshi-thread2---Thread-3
System.out: ceshi-thread1---Thread-2
System.out: ceshi--handler5--5---Thread-3
System.out: ceshi--handler1---3---main
System.out: ceshi---handler2---4---main
System.out: ceshi--handler6---6---main
System.out: ceshi--handler1---1---main
System.out: ceshi---handler2---2---main

Thread和Handler的关系
一个Thread里同一时间可以持有n个Handler
这里是mainThread持有handler1,handler2,和handler6!

但是Handler同一时间,能有持几个Thread?1个。
简单的问:同一handler发送的消息,能被几个thread接收到?
不同的thread里的handler接收消息就是各自的handleMsg方法,实际是msg.target.dispatchMsg,而msg.target就是之前那个调用sendMsg的handler,说白了就是一一对应关系。


Thread和Looper的关系
一个Thread里同一时间只能存在一个Looper
由Looper类的prepare()方法可知

 private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

所以不能在主线程里调用Looper.prepare(),因为主线程在初始化的时候已经初始化了一个Looper。
代码位置在Activity类里找ActivityThread,ActivityThread的main方法

public static void main(String[] args) {
        省略..
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

反过来,Looper同一时间也只能持有一个Thread

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

子线程开启,没有looper,想用handler,就得looper.prepare(),那么就会new一个looper,Looper的构造方法就绑定了当前thread。


Looper和ThreadLocal的关系
在Looper类里,还有个饿汉式初始化ThreadLocal

 // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal sThreadLocal = new ThreadLocal();

也就是Looper同一时间只有一个threadLocal
反过来,threadLocal.set方法实际是内部维护一个map

 public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

threadLocal同一时间也就只有一个Looper咯

Looper prepare的时候,
先检查 threadLocal,先get,看能不能拿到looper
再set,把looper set到threadLocal里
ThreadLocal 的get方法,很诡异
看起来是key,value,key是thread,value是looper

实际上是获取 thread里私有的threadLocal,
因为ThreadLocal.ThreadLocalMap是线程私有的。
这个ThreadLocalMap是ThreadLocal的静态内部类。

然后并不是真正的map。而是一个 Entry数组。
这个数组存的方式也很奇怪,index是threadLocal的hashCode
value是Entry。
entry的key是 ThreadLocal,value是其持有的私有对象值,这里是looper

然后,这个entry,继承的是一个WeakReference>
这个能保证,weakReference里的threadLocal 就不算强引用,可以正常回收,threadlocalMap也就可以回收,这样里面的一些私有变量就可以被回收。

举个例子, userInfo放到threadLocal里,做线程私有变量,当userInfo不用了,userInfo==null,
但是threadLocal还持有userInfo(集合持有),threadLocal生命周期跟thread一起,可能这个thread就一直没释放,也就没回收,导致内部的threadLocalMap就一直保留着userInfo.

这里就可以做到,threadLocal的remove函数,会主动清理掉entry,避免集合引用导致的泄露。

ThreadLocal看看这篇的学习方法吧,挺好的
https://mp.weixin.qq.com/s/XZIf5tCU03Upscdl1mQ8qA


looper和messageQueue的关系
一一对应,不多说了。


Handler和Looper的关系
一个handler同一时间只能持有一个Looper,看构造方法就可以知道了。

但是一个Looper统一时间可以持有多个Handler
(就是mainLooper持有了handler1,handler2)
如果在子线程里这样创建handler,实际这个handler也属于主线程,也就是被mainLooper持有

Thread thread2 = new Thread() {
        @Override
        public void run() {
            super.run();
            Looper.prepare();
            Handler handler5 = new Handler(Looper.getMainLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    System.out.println("ceshi--handler5--" + msg.what + "---" + Thread.currentThread().getName());
                }
            };
            Looper.loop();
    }
};

你可能感兴趣的:(IntentService/HandlerThread/Handler源码阅读)