这是叶扬在锻炼他的精神力,当精神力被锻炼到一定程度后,便是能够形成实质,并且伴随着精神力的强化,叶扬的脑域也会被彻底的扩展,那他也就会出现一些超越常人的能力,也就是所谓的超能力。

赵廷玉一路北上,每次来和李庆安开会他一定会叫上韩志,但每次都平安无事,时间久了,他的警惕性也慢慢放松,今天他照例邀请韩志一同来开会,不料韩志却感恙了,赵廷玉心急,便自己带领亲兵来了。

又到层林尽染时,你觉得哪里的枫叶最漂亮?

官道上尘土飞扬,几个月滴雨未下,两边的树木都被尘土染成了黄色。已经不见一丝绿意,路边的小河干涸见底,土地皲裂有一指宽,官道是两县的分界,东面是许昌县,西面则是长葛县。
这等修为,莫说三清,就是麒麟大禹恐也能将其打得狼狈不堪,难道如来就不怕有人将其灭杀么?而佛门地狱中那个泥犁菩萨,却又厉害的令人发指,凭后土之能竟几无还手之力。

一回到家,许莹莹就立刻认真的查阅材料,然后打开笔记本开始找案例,这一忙下来,她都忘记了时间,等到感觉有些饿了,想到要吃饭的时候,已经是凌晨一点半,于是拖着有些疲惫的身子朝厅堂的冰箱走去。

finally


        如果您的app中没有使用过Handler,那您一定是写了个假app;如果您笔试题中没有遇到Handler相关的题目,那您可能做了份假笔试题;如果您面试中没被技术官问到Handler的问题,那您也许碰到了个假面试……因为它太重要了,也太容易因使用不当二带来很多问题。笔者工作这么多年,对Handler经常感觉如芒在背,如鲠在喉,使用起来经常不太自信,所以不得不专门回过头来好好研究和整理一下,解决掉这个大麻烦。如果您也有我这样的感受,希望本文能给您带来一定的帮助。为了方便理解和记忆,笔者把Handler机制类比到生活中具体的场景,希望能够做到通俗易懂,加深读者的印象。另外,笔者技术有限,有描述不当的地方,请雅正。

 

        本文主要分为如下几个部分

        一、痴汉委托媒婆送情书:Handler发送Message

        二、媒婆把情书存入信箱:将Message插入到MessegeQueue消息队列

        三、妹子派丫鬟取情书:Looper取消息

        四、妹子读情书:对消息的处理(注意:这一节是重难点,对理解Handler反馈消息比较重要,后面还会继续讲到)

        五、妹子的回应:消息回调

        六、妹子对痴汉说:“你的都是我的,我的还是我的”:回调函数所在线程问题分析

        七、做好安全措施:Handler内存泄漏问题

        八、发福利,撒狗粮:面试要点       

 

        Android中子线程和UI线程(即主线程),就像古时候的痴男和怨女。某天,一痴汉看上了一妹子,一见钟情,想要表达爱意和提亲。可是,那个时代,即使再心急火燎的,也不能冒冒失失直接去找妹子求婚啊。怎么办呢?痴汉顺理成章想到了媒婆——Handler!稍有一点Android开发基础的朋友都知道“主线程不做耗时操作,子线程不更新UI ”。可是当子线程完成耗时操作,需要更新UI,要怎么办呢?Handler作为一名经验老到的媒婆,在痴汉(子线程)和妹子(UI线程)之间扮演了总要的信使角色。

 

        一、痴汉委托媒婆送情书:Handler发送Message

                                

             ① sendMessage(Message msg)源码截图

                  

             ② sendEmptyMessage(int what)源码截图

                  

                  

             ③ post(Runnable r) 源码截图

                  

                  

             ④ postDelayed(Runnable r, long delayMillis)源码截图

                  

         看,多么熟悉的面孔!!!没错,sendMessage(...),sendEmptyMessage(...), post(...), postDelay(...),平时使用最广泛的四个方法,媒婆Handler主要就是靠的这四招,替子线程向UI线程递信(发送Message)的。从上图中左上角我们可以直观地看到,这四个方法都直接或间接递地在调用sendMessageDelay(...)方法。殊途同归,Handler无论使用何种方法,其宗旨都是在想办法传递信息。无疑,Handler这个媒婆很聪明,会根据不同的场景选择使用其中的一种合适的方法。

         

         二、媒婆把情书存入信箱:将Message插入到MessegeQueue消息队列

         sendMessageDelay(...)层层往下走,会调用enqueue(...)方法。该方法会触发MessageQueue调用自己的enqueueMessage(...)方法。

          

          MessageQueue中enqueueMessage(...)方法的关键代码如下:

          

           MessageQueue,就像妹子的信箱,媒婆(Handler)送来的情书(Message)就被存储这个里面。它的学名叫做消息队列,从源码总可以看到,它采用链表的形式,无限循环将消息加入其中。

 

        三、妹子派丫鬟取情书:Looper取消息

        情书总是不期而至,媒婆把情书放入信箱,却没有通知妹子,妹子又如何知道意中人有信件送达呢?原来,妹子是大家闺秀,专门有丫鬟伺候她,时时刻刻检查着信箱。这个丫鬟就叫Looper,扮演着重要的角色。

        Looper中有个loop( )方法,正如以下代码所示,本质上是调用MessageQueue.next( )方法。这个方法可以对应MessageQueue.enqueueMessage(...)方法,一个无限循环存入Message,另一个就无限循环取出Message。就是Looper这个勤劳的丫鬟在不停查看信箱,有情书到了,就取出来交给妹子。如下代码显示了Looper从消息队列中取消息的关键代码,可以看到这是一个无限循环的过程。这里,要着重注意第14行, msg.target在前面的enqueueMessage(...)方法中有提到,"msg.target = this", 说明它就是Handler的一个实例,对应UI线程中new的Handler实例,它调用了dispatchMessage(msg),该方法的作用就是安排处理Message,后面(妹子读情书)中会详细讲到。

           

 1 public static void loop() {
 2         final Looper me = myLooper();
 3         if (me == null) {
 4             throw new RuntimeException("No Looper; Looper.prepare() wasn"t called on this thread.");
 5         }
 6         final MessageQueue queue = me.mQueue;
 7         ...for (;;) {
 8             Message msg = queue.next(); // might block
 9             if (msg == null) {
10                 // No message indicates that the message queue is quitting.
11                 return;
12             }
13            ...try {
14                 msg.target.dispatchMessage(msg);
15                 ...
16             } finally {
17                 ...
18             }
19             ...
20             msg.recycleUnchecked();
21         }
22     }

         

       那么问题来了,Looper又是从哪里来的呢?难道是和孙猴子一样从石头中蹦出来的?Android程序本质上也是java程序。我们总是疑惑,为什么我们的app中怎么也找不到main( ) 入口?哈哈,其实仍然是有main( )入口函数的,在ActivityThread中:

   

1 public static void main(String[] args) {
2         ...
3         Looper.prepareMainLooper();
4         ...
5         Looper.loop();
6         ...
7     }

         豁然开朗了吧,Looper的身世都在main(...)方法中!Looper.prepareMainLooper()作用是生成一个Looer实例,然后就Looper就调用了loop( )方法,开启了她作为丫鬟勤劳的一生。

        只能说妹子的命是真好,有个好爹,她从出生开始,老爹就为她安排好了体贴的丫鬟,全心全意地为她服务着。

 

        四、妹子读情书:对消息的处理(注意:这一节是重难点,对理解Handler反馈消息比较重要,后面还会继续讲到)

       上一节 ”妹子派丫鬟取情书”中提到了该方法(loop( )方法中的第14行)。此刻,情书已经到了妹子的手中, 妹子要开始享受地读情书了。

        

        这里,msg.callback就是Runnable类型,看到这里,有没有想到点什么呢?是不是想到了post(Runnable r)和postDelay( ...)的参数?没错,这里就有如下两种情形

         (1) 如果您在发送消息的时候选择的是post(...)或者postDelay(...):

              回头看第1节中,这两种方法直接或间接调用sendMessageDelayed(Message msg ,long delayMills)时,传入的Message实例方式为getPostMessage(Runnable r)

             

             看到“m.callback = r”这一行,msg.callback != null就成立,后面调用handleCallback(msg):

           

             这里的run( )就是调用了post(...)或postDelay(...)中参数Runnable实例的回调方法run( ),在run()中UI线程对界面更新。在这里,可能会有读者非常疑惑,子线程中怎么能直接更新UI呢?这里是不是笔者犯糊涂搞错了?其实这里,run( )中所在的线程仍然为UI线程,我们会在后续的小结中给出分析结果,到时候千万不要惊掉下巴噢!

         (2) 如果选择的是sendMessage(Message mgs)或sendEmptyMessage(int what):

              这两种方法传递给sendMessageDelayed(Message msg ,long delayMills) 的实例msg,一般有两种途径,一种是new Message()(不推荐),另外一种是       Message.obtain( )。

             

             

             查看上述源码可知,根本没有msg.callback啥事了,其值就为null了。msg.callback != null不成立,从而走else分支,这里又要做出条件判断了。

            咳咳,注意了,笔者又要上思维导图了

            

             Handler有5个构造函数, 但实质上,都是调用的如下构造函数:

 构造函数1 
1
public Handler(Callback callback, boolean async) { 2 ... 3 mLooper = Looper.myLooper(); 4 if (mLooper == null) { 5 throw new RuntimeException( 6 "Can"t create handler inside thread that has not called Looper.prepare()"); 7 } 8 mQueue = mLooper.mQueue; 9 mCallback = callback; 10 mAsynchronous = async; 11 }
构造函数2
1
public Handler(Looper looper, Callback callback, boolean async) { 2 mLooper = looper; 3 mQueue = looper.mQueue; 4 mCallback = callback; 5 mAsynchronous = async; 6 }

        我们回过头来看看dispatchMessage(...)方法,mCallback就是实例化Handler时传入的。如果实例化时传入了Callback实例,则mCallback != null,这样就调mCallback .handleMessage(msg),在实例中override该方法。而如果在实例化的时候,没有传入Callback实例,那就调用自己的handleMessage(...),如下所示,其实它是个空函数,也需要在实例中去override。

       

       此时可刻,读者应该很清楚咱们的妹子是如何处理信件了的吧,如果还不清楚,请对照源码截图,再看一遍 ^_^。

 

       五、妹子的回应:消息回调

       妹子看完了情书,总得给痴汉一些反馈吧,是开心?还是生气?要不然痴汉长期得不到反馈,说不定心灰意冷,要移情别恋。

       对于妹子的反映,这里接着上一节内容继续往下看。        


 post(...)和postDelay(...)的情况更新界面
 1 new Thread(new Runnable() {
 2             @Override
 3             public void run() {
 4                 new Handler().post(new Runnable() {
 5                     @Override
 6                     public void run() {
 7                         mTextView.setText("收到你的信,无比开心,咱们小花园见");
 8                     }
 9                 });
10             }
11         }).start();
12 ...
13 new Thread(new Runnable() {
14             @Override
15             public void run() {
16                 new Handler().postDelayed(new Runnable() {
17                     @Override
18                     public void run() {
19                         mTextView.setText("收到你的信,无比开心,咱们小花园见");
20                     }
21                 },1000);
22             }
23         }).start();

 

 sendMessage(...)和sendEmptyMessage(...)的情况更新界面
1
private Handler mHandler = new Handler() { 2 @Override 3 public void handleMessage(Message msg) { 4 super.handleMessage(msg); 5 switch (msg.what) { 6 case 0x001: 7 mTextView.setText("收到你的信,无比开心,咱们小花园见"); 8 break; 9 default: 10 break; 11 } 12 } 13 }; 14 ... 15 new Thread(new Runnable() { 16 @Override 17 public void run() { 18 Message msg = Message.obtain(); 19 msg.what = 0x001; 20 mHandler.sendMessage(msg); 21 } 22 }).start(); 23 ... 24 new Thread(new Runnable() { 25 @Override 26 public void run() { 27 mHandler.sendEmptyMessage(0x001); 28 } 29 }).start();
说明:这种就是上一节中第二中情况,笔者平时自己写代码的时候,没有在new Handler的时候传入Callback,这里就override了handler自己的handleMessage方法。

 如此一来,痴汉和妹子就过上了甜蜜的生活了。

 

      六、妹子对痴汉说:“你的都是我的,我的还是我的”:回调函数所在线程问题分析

      还记得第4节中第(1)小节中留下的疑问吗?就是篇中的红色部分。要说new Handler中override的handleMessage(msg)方法在UI主线程之中,相信读者都不会有异议,就像妹子(UI主线程)说:"我的还是我的"。可是post(...)和postDelay(...)中Runnable的回调方法run(),也是执行在UI主线程中,那就有疑惑了。

     无图无真相,先来看看一个例子:

     

    打印结果为

    

       实验结果这证明了之前的结论。其实,如果从基础语法来分析,Runnable只是一个接口,run( )是它的一个抽象方法。还是第4节中红色部分提到过,中途调用了msg.callback.run( ),就是调用的Runnalbe实例的run(),就是一个普通的回调方法而已,而不是开辟的一个子线程,不能因为看到run( )就认为是多线程。这一点如果java多线程基础比较扎实,就容易理解了,这里不做深入描述,请读者自行研究,有机会的话再单独写一篇java多线程的文章。

       所以,妹子(UI线程)对"霸道"地对痴汉(子线程)说:“你的都是我的,我的还是我的”。^_^

       结论:无论是override的handleMessage(msg)方法,还是这里的run( ),都是在主线程中完成的。仍然搞不清楚原理的,可以先记住这个结论。

 

      七、做好安全措施:Handler内存泄漏问题

      虽然是合法夫妻,但激情燃烧的同时,必要的安全措施还是要做的。

      Hander内存泄漏的问题,也是很常见的问题。这里推荐别人写得不错的博客,https://blog.csdn.net/javazejian/article/details/50839443

     

     八、发福利,撒狗粮:面试要点

      Handler既然如此的重要,那笔试面试啥的,都不在话下了。笔者这么多年参加面试情况看 ,80%的情况是要和笔试或者和技术面试官聊到的。所以,如果你要找工作了,一定要好好组织语言,把自己所知道的说清楚。关于这一块,有如下几个要点(根据自己经验终结):(1)如果是笔试题,一般会问:Handler,Message,MessageQueue,Looper,ActivityThread之间的关系。(2)如果是技术官问,一般会让你说说Handler机制。这里就按照我文中的思路,按照 Message封装消息,Handler发送Message,MessageQueue存入消息,Looper.loop( )循环去消息,发送到UI线程中,回调的方式给出回应即可。(3)聊到内存泄漏的时候,可以扩展到Handler引起的泄漏问题,可以加分。

     

       目前先总结到这里,后续会对文中提到的子线程问题,内存泄漏等问题展开,或单独成文,或在本文中补充。笔者知识有限,有很多不足之处,请不吝赐教。也感谢您的阅读,希望能对读者有一定的帮助,即便读者可能很少很少,谢谢!!!

 

   

 

当前文章:http://hnhdqp.com/play/soa8zrrczk.html

发布时间:2019-03-23 00:00:00

你从来都不知道今天在地铁里能遇见谁 亲爱的,没有什么比努力赚钱更让你理直气壮 2015年全面二胎,你生不生? 原创:在亲密关系中如何相互依赖与共生 抱歉这么晚才找到你 失恋了怎么办? 向死而生:从《道士下山》到天津爆炸,来谈谈生死 来得及

妹子,你向往什么样的爱情? 恋物癖:难以启齿的诱惑 跳在乐趣消失前 春天的养护 谈早恋与儿童的异性交往 不可小觑的幼儿园“阴影” 为什么说,男人天生就是“大色狼” 没有仪式感的爱情,不会长久 新时代的养育观——你知道么? 你真的适合创业吗?答案是“未必”! 罗李华语录 收盘:大盘收阴,市场堪忧! 我看目前很火的IT小说。。。 罗李华:金牛座2016年运势 时代病的白描 别和自己过不去 你是那个内心强大的人吗? 朱丹,爱自己的你好美 我们的生活有没有本末倒置

编辑:丁伯帝

相关新闻

成年人失踪“24小时才立案”?

2019-03-23 00:00:00

银川幼牙汽车服务有限公司

探索互联网+农业 京东绿安宁夏馆开馆

2019-03-23 00:00:00

金昌磐扑沟市场营销有限公司

破天荒!Flyme有望提前完成三款机型适配工作

2019-03-23 00:00:00

陵水滦诩垦汽车用品有限公司

三星Galaxy Tab3 8.0平板售价约为2670元

2019-03-23 00:00:00

乌鲁木齐细促扛美容美发化妆学校

热门推荐

  • 网页版仿Excel效果组件--handsontable拓展运用
  • 俄罗斯载71人客机坠毁 事发时无极端天气情况
  • 重新上阵,戈恩或将再次担任雷诺CEO
  • 100%羊毛,豹邦旗舰店男士V领/圆领针织纯羊毛衫88元(410元券)
  • 索尼新广告用RAP唱出了22部PS4游戏:今年的大作都在这了
  • 鲜醇回甘,安吉原产地雨前珍稀特级白茶125g装39元(50元券)
  • 黑土地焕发新活力,“加减法”播下新希望
  • 组图:活到老学到老!61岁老人报考高校研究生
  • 再次引领潮流,苹果Animoji成社交网站新的风景线
  • 卖馒头月入6万卖馒头大爷如何发家致富?
  • 河北新闻网版权所有 本站点信息未经允许不得复制或镜像 法律顾问:真有人格分裂吗? 17道题自测心理健康
  • 原创:面对灾难最好的帮助—倾听篇 copyright ? 2000 - 2016
  • 新闻热线:0311-67563366 广告热线:0311-67562966 新闻投诉:0311-67562994
  • 冀ICP备 09047539号-1 | 互联网新闻信息服务许可证编号:1312006002
  • 广播电视节目制作经营许可证(冀)字第101号|信息网络传播视听节目许可证0311618号
  • 频繁“癫痫发作” 原来是“曲马多”惹的祸 儿童为什么自伤? 女性最佳生育年龄延后 30-39岁生的娃更聪明? 失恋女人心(失恋心理)