PS:刚刚都快写完了,竟然提示编辑器挂了,再进来啥都木有了,坑啊,坑啊,啊
我们在一个子线程中创建Handler的实例,如下所示
PRivate Handler mHandler; private class LooperThread extends Thread{ @Override public void run() { super.run(); mHandler = new Handler(); }}在运行的时候会报错”Can’t create handler inside thread that has not called Looper.prepare()”,根据字面意思很清楚的可以看出是因为我们没有调用Looper.prepare()方法导致的。我通过Looper.prepare()方法的源码去分析消息机制的内部是怎样的原理,以及Looper类在消息机制中承担了何种角色。 首先我们查看Looper.prepare()方法的源码。 结合这两段代码可以看出Looper.prepare()方法的作用就是创建一个Looper的实例并且将其放入到ThreadLocal中去,我们知道ThreadLocal可以保证不同线程间的数据互不干涉,在通过new Looper()可以看出Looper的实例化过程就是创建一个消息队列,和获取当前的子线程,将其放入到ThreadLocal中去,所以我们可以看出Looper、Queue、Thread是一一对应,每个子线程之间互不干涉。 在调用Looper.prepare()之后new Handler()正常,通过源码可以看到 Handler实例会将对应的ThreadLocal中的Looper取出,通过Looper来管理监听消息队列。在Looper.prepare()方法源码的注释中可以看到,Looper.loop()方法是开始轮询消息队列。 调用Looper.loop()后会阻塞子线程轮询消息队列。调用Looper.quit()结束轮询。 综上,Looper、线程、队列是一一对应的,不同的子线程存在不同的Looper在ThreadLocal中互不影响。值得注意的是,主线程自动创建Looper,而子线程需要手动创建。所以官方写法为:
消息的处理过程分为:入队、出队、处理。 消息入队的过程实质上就是发送消息的过程,Handler发送消息方法: post()、postAtTime()、postDelayed()、postAtFrontOfQueue(); 通过源码我们可以看到前三种方式都会调用到 正常来讲,消息的入队过程就相当于银行区号排队,我们从1号开始发送号码然后递增,来的越早号码越小越先出队,这里参数”uptimeMillis”就相当于号码牌。 我们再看postAtFrontOfQueue()方法的源码 可以看出其实它的原理和前三个方法是一样的,不过是参数”uptimeMillis”被置为常量0,这就相当于银行大家都是排队时突然过来一个Vip金卡用户,队列会把这条消息排在队伍最前面优先出队(银行优先处理)。
Thread:线程负责业务逻辑。 Handler:消息的发送和处理。 消息队列:保存消息。 Looper:轮询消息。
新闻热点
疑难解答