相约去吃二回好吃的食品

在前边的博文中,讲过局地和Handler有关的知识,例如:

必赢棋牌app官网 1

Android
二十八线程—-AsyncTask异步职责详解 

01

Android十2线程—-异步音信处理体制之Handler详解

臭脊花鱼的花香,随着你走入茶楼里的流水长廊,低处烟雾缭绕,水声潺潺,空中无形的深意紧随吸引你的专注力。鼻子不会诈骗人,眼睛4下寻摸,看到“微微臭,块块蒜瓣儿肉”店铺的旗号,商户菜品的广告介绍映入眼帘。

今天再把Handler的知识回看总括一下。

桌桌必点古板做法臭鳌花鱼,京城里的门下也都是南腔北调的人,不一会儿,脸上的红晕不分老少汉子儿,少女妇人,齐刷刷地挂在颧骨、眉眼间。甭管是喝不饮酒,若只喝几口热乎乎的菊白茶,也全然是一副沉醉在美味佳肴中的模样。

 

点上一壶清酒,初借酒劲儿,频频举箸,滚烫白白的微辣鱼肉、细粉条再入口,想慢条斯理地当三回雅人韵士,不容许做获得!用餐时光被美味的食物的热度、美酒的度数控制得忽慢忽快的,渐入佳境。

本文包罗与Handler有关的以下难点:

那小心脏被山东菜饭馆自制1八度米酒带着跑,稍微喝猛几口,突突地跳起来。醉酒状态那是不会让其得逞的,一向以来掌握控制好饮酒的旋律,向来未有失去过理智,“喝趴下”在吃酒习惯里还没被圈定过。

  (1)Handler的作用

02

  (贰)为啥Android中要统一筹划为只万幸UI线程中去更新UI呢?

对美味的食品、美酒的钟情,像是对美好生活的想望一般,即维持鉴赏、敬畏、暖意、清静自由的心气,从容涌动在炙热的口感与烟火气缭绕的条件中,仰天壹笑,春风得意浪漫;又保持自重的人之精神,不因一时一贯的引发,被众生之相所吸引,而失去自笔者控制能力。

  (叁)Handler的八个可怜

品酒之后能够留下本人的那一小段,值得斟酌滋味的时光,正是酒劲儿上头那阵子,顺带拿捏着1身的血流,酸懒而竭尽全力控制着欲望升温,保持住清醒的最后一道防线,频频运营温暖的心跳,不让它显示因酷热而点火过猛的情景。

  (肆)Handler、Looper MessageQueue之间的涉嫌(源码角度)

不禁想起了已经到过的中山,喜欢那里的糯威尼斯绿酒,喜食江东风味的蒸碗小菜,相当有意见的是不曾在题扇桥旁的本土酒馆,吃上1些小蒸菜、配他家自酿的黄酒,只把满屋子的花香留在了纪念里。但是地面街巷里的自制果酒倒是尝试过。
​​​

  (5)跟线程相关的Handler,即HandlerThread(源码角度分析)

就好像又二遍走进了巷子深处的幽静楼影处,午后太阳透过斜窗的线条清晰画在桌上,无事的假期,放松的心思,举杯小抿一口,眼睛瞧着巷子角落公用水阀旁淘米洗菜的大妈,一杯红酒,就成为了分享生活的助推器,细细聆听水流冲刷的动静,静心等候酒品好、酒量非常的小、自笔者控制力强、感恩心态相仿的亲朋出现。

  (6)主线程往子线程发新闻

03

 

酒友,尤其是女男子中的酒友,最难寻觅到!亦大概,棋逢对手、将遇良才的酒友,才是世间最难遇见的珍宝!你坐在友人对面,酒后吐真言、临危不惧的胆量,虽值得表彰,不过应当了解饮酒过量误伤肉体的道理,看清喜乐印刻在餐桌上的笑痕,壹旦被欲望牵制了,真性情的阴影也变成了令人怅然的叹息。

一、Handler的作用:

未曾让朋友饮酒尽兴,皆因不胜酒力,头脑发晕而谈话表明却不有失常态态,此刻,浓郁美味趁虚而入的补给进来,那是四个人饮酒之时,自动找到了心灵落脚的平衡点。

(1)在非UI线程中成功耗时操作,在UI线程中去更新UI。

(贰)能够在主线程中发送延时新闻。

名酒配佳肴,美言醉人心,借助徽之味,吹梦里见到徽州。

 

心里窃喜,京城里又寻到一处吃正宗臭鳜花鱼的地点,想着要带上友人1起来品尝评价壹番,先在私底下打上5星级标记,从前收集到的那多少个茶馆排行,自动降级向后退。

二、为啥Android中要设计为只幸亏UI线程中去更新UI呢?

04

(1) style=”color: #0000ff;”>杀鸡取卵拾二线程并发难点(根本原因)

(二)升高界面更新的习性难点

(叁)架构划设想计的简易

第3遍吃到那红烧臭母猪壳,是三年前在京城东肆环垡头路方向的多个叫“无为小馆”里。酒店墙面挂着介绍无为板鸭、臭季花鱼由来的文字和图片。今后因周边环境改造,已搬迁不见了其踪迹。

您也许会说,既然是担心二十四线程并发难点,那作者在子线程中加锁进行更新UI可以还是不可以吧?你如此想的话,会不难造成UI卡顿的,而且品质也不好。

无为隶属于湖南省铜陵市,县名取“思天下安于无事,无为而治”之意。这些店的小业主是凤台县人,垡头路上连成片的建材供应商,大多数都是西藏老乡,他们洽谈工作的去处,就是那小小的鲁菜馆。

注1:大多数面试者很难去说出1个令面试官满足的答案。

点了东北菜家常口味的腊肉炒蚕豆、臭清炒美芹,菜品壹上桌,被业主的手艺俘虏了芳心。石黄的洋芹、鲜蚕豆从本土快递运来,肥瘦相间的无花咸肉也是邻里风味,加上细条花青熏干的味重刺激,理智主动加了1瓶装朗姆酒酒合作美味,在主打菜臭季花鱼还未露面以前,一下子把胃里馋虫急急炸醒。

注贰:关于八线程,这里举二个例证,比如说银行取款的题材。通常意况下,银行卡余额无法简单取款金额,假若八线程实行取款的话,就会促成线程不安全。

臭母猪壳又称腌鲜鱼,“腌鲜”在徽州当地点言中有臭的意趣。闻着臭吃着香,守旧红烧臭脊花鱼的做法服从山东菜“汤汁厚重,味鲜浓郁”的口感,特点重视用油、珍惜色泽、器重火功。

注三:Android中因故说架构简单,是因为帮大家封装了广大更新UI的操作。

率先次尝试,有一种身处徽州禹会区农户庭院的感觉到,吹着竹林旁送来的清劲风,围着热腾腾的铁比目鱼锅,红黄椒、鲜笋小丁、鲜肥肉丁等辅佐,配着米饭,密集轰炸着味蕾,冒汗、脸红,谈话内容也越加丰裕。

 

05

三、Handler的四个十三分:

登时获得同行亲属的提示,注意收集查询一下关于楚菜的消息资料,等之后有机会到山东省岳西县、博望区、颍泉区走走,看看西藏特有的绿树丛荫、沟壑纵横、气候宜人等地理条件,寻访人文环境的开拓进取转移,体验本地居民的伙食民俗。

在运用Handler时,常常会产出以下多个十一分:

无意看到了1篇介绍鲁菜的文章,立即将西藏籍小说家赵焰的《徽之味》那本书购买了归来,三年时光里读书过它无数遍。它的人影也趁机理智的火车旅行,到过被称作“画里乡村”的山西宏村镇(巢湖市东至县辖镇)、周庄、湖南省佛山、温州等地。

(壹)CalledFromWrongThreadException:那种非凡是因为尝试在子线程中去更新UI,进而发生非常。

实际上,赵焰的《晚清三部曲》(《晚清有个李鸿章》、《晚清有个曾涤生》、《晚清有个袁大头》)等在中华夏族民共和国有较大影响,理智心里一贯想购买收藏在书囊中,希望以此心愿能顺畅排入新一年购书清单,相当慢完结。

(2)Can’t create handle inside thread that ha not called Looper.prepared:是因为我们在子线程中去创制Handler,而产生的百般。

那本《徽之味》中的好吃的食品随笔,一点都不小满足了理智对感兴趣的臭桂花鱼文化、无为板鸭的文化学勘探求。书中介绍内容与首都酒店广西中国广播公司告剧情相比较,引经据典、制作进度等都某个出入,书中的知识感觉越是详实且富有说服力。

我们接下去通过代码来把那多个10分演示一下。

06

1、子线程中更新UI的老大:

在巴黎每一回吃到臭花鲫鱼,都会幸免不住欢喜的心境,微信发给好友1些图片,几句醉言,誓誓旦旦宣称要带她去品尝1番。

(1)activity_main.xml:

唯独,此次的存续动作,却与眼下分裂,静静压下了美味的食品图片,原来心里是想等2个适中的时机面世,等娱心悦目的休假开端,等时段走到相聚的那一刻,等对清酒的追忆再一次掀起着嗅觉,酒友的天平微微倾斜指向了你的这么些主旋律,那么,厚爱有加的诺言,一定会落到实处的!

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world"/>

    <Button
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="按钮"/>

</RelativeLayout>

必赢棋牌app官网,终极,配一张朦胧的红烧臭菊花鱼照片,就不打上那一个酒馆的名字,想精晓呢?来猜1猜呗!

 上方代码中,二个文件,1个按钮,代码相比容易。

理智2018年01月13日

(2)MainActivity.java:

 1 import android.app.Activity;
 2 import android.os.Bundle;
 3 import android.view.View;
 4 import android.widget.Button;
 5 import android.widget.TextView;
 6 
 7 public class MainActivity extends Activity {
 8 
 9     private TextView tv;
10     private Button btn;
11 
12     @Override
13     protected void onCreate(Bundle savedInstanceState) {
14         super.onCreate(savedInstanceState);
15         setContentView(R.layout.activity_main);
16         tv = (TextView) findViewById(R.id.tv);
17         btn = (Button) findViewById(R.id.btn);
18 
19         //点击按钮后,尝试在子线程中更新UI
20         btn.setOnClickListener(new View.OnClickListener() {
21             @Override
22             public void onClick(View v) {
23 
24                 new Thread(new Runnable() {
25                     @Override
26                     public void run() {
27                         tv.setText("smyhvae");  //子线程中更新UI
28                     }
29                 }).start();
30 
31             }
32         });
33     }
34 }

上边代码中,宗旨代码是第贰七行:点击按钮后,在子线程中更新UI。

运维程序后,点击按钮,效果如下:

必赢棋牌app官网 2

那时,我们来看一下后台的log日志:

必赢棋牌app官网 3

上海教室中报的不当日志就是因为大家在子线程中去更新UI。

 

化解方案:

  在子线程中创制Message音讯,通过Handler发给主线程,之后在Handler的handleMessage方法中得到Message音信,进而处理更新UI界面。代码如下:

 1 import android.app.Activity;
 2 import android.os.Bundle;
 3 import android.os.Handler;
 4 import android.os.Message;
 5 import android.view.View;
 6 import android.view.View.OnClickListener;
 7 import android.widget.Button;
 8 import android.widget.TextView;
 9 
10 public class MainActivity extends Activity implements OnClickListener {
11     public static final int UPDATE_TEXT = 1;
12     private TextView text;
13     private Button changeText;
14 
15     //程序一加载,直接在主线程中创建Handler
16     private Handler handler = new Handler() {
17         public void handleMessage(Message msg) {
18             switch (msg.what) {
19             case UPDATE_TEXT:
20                 text.setText("Nice to meet you");
21                 break;
22             default:
23                 break;
24             }
25         }
26     };
27 
28     @Override
29     protected void onCreate(Bundle savedInstanceState) {
30         super.onCreate(savedInstanceState);
31         setContentView(R.layout.activity_main);
32         text = (TextView) findViewById(R.id.text);
33         changeText = (Button) findViewById(R.id.change_text);
34         changeText.setOnClickListener(this);
35     }
36 
37     @Override
38     public void onClick(View v) {
39         switch (v.getId()) {
40         case R.id.change_text:
41             new Thread(new Runnable() {
42                 @Override
43                 public void run() {
44                     Message message = new Message();
45                     message.what = UPDATE_TEXT;
46                     handler.sendMessage(message);
47                 }
48             }).start();
49             break;
50         default:
51             break;
52         }
53     }
54 }

 上方第五四行代码也能够换来:

Message message = handler.obtainMessage();

  

二、在子线程中开创Handler的要命:

MainActivity.java:

 1 import android.app.Activity;
 2 import android.os.Bundle;
 3 import android.os.Handler;
 4 import android.widget.TextView;
 5 
 6 public class MainActivity extends Activity {
 7 
 8     private TextView tv;
 9 
10     @Override
11     protected void onCreate(Bundle savedInstanceState) {
12         super.onCreate(savedInstanceState);
13         setContentView(R.layout.activity_main);
14         tv = (TextView) findViewById(R.id.tv);
15 
16         //尝试在子线程中去创建Handler
17         new Thread(new Runnable() {
18             @Override
19             public void run() {
20                 new Handler();
21             }
22         }).start();
23     }
24 }

 运转程序后, 报错如下:

必赢棋牌app官网 4

  

肆、Handler、Looper MessageQueue之间的涉及:(源码角度)

    假如要问到Handler,这几个题材大旨是面试必问的。

原理分析:

Handler是Android类库提供的用来发送、处理音讯或Runnable对象的拍卖类,它构成Message、MessageQueue和Looper类以及当前线程实现了三个音信循环机制,用于落实任务的异步加载和拍卖。整个异步音讯处理流程的示意图如下图所示:

必赢棋牌app官网 5

据他们说地方的图纸,大家今日来分析一下异步新闻处理体制

  • Message:音信体,用于装载需求发送的目的。
  • Handler:它一直接轨自Object。功用是:在子线程中发送Message恐怕Runnable对象到MessageQueue中;在UI线程中收到、处理从MessageQueue分发出来的Message也许Runnable对象。发送信息一般选择Handler的sendMessage()方法,而发出去的音信经过处理后最后会传送到Handler的handlerMessage()方法中。
  • MessageQueue:用于存放Message或Runnable对象的音信队列。它由相应的Looper对象创造,并由Looper对象管理。每个线程中都只会有一个MessageQueue对象。
  • Looper:是各样线程中的MessageQueue的管家,负责接收和散发Message或Runnable的劳作。调用Looper.loop()方法,正是叁个死循环,不断地从MessageQueue中取新闻:假设有音信,就取出,并调用Handler的handlerMessage()方法;倘诺未有新闻阻塞。

今日得以做出如下总括:

(一)Handler负责发送音讯,Looper负责接收Handler发送的新闻放到MessageQueue,Looper又将新闻回传给Handler自个儿。

(2)一个Handler对应一个Looper对象,叁个Looper对应二个MessageQueue对象(Looper内部蕴藏2个MessageQueue),一个Handler能够扭转三个Message。

(三)Handler正是当众给外部线程的接口,用于线程间的通讯。Looper是由系统协理的用来创建和管理MessageQueue的隶属于3个线程的大循环处理对象,而Handler是用来操作线程内部的新闻队列的,所以
           Handler也不可能不依附三个线程,而且不得不是两个线程。

(4)由于Handler是在主线程中创立的,所以那时handleMessage()方法中的代码也会在主线程中运行,于是大家在此地就足以安慰地展开UI操作了

 

生活中的例子:

必赢棋牌app官网 6

上海教室中,能够如此清楚:开会时,笔者(Handler)想中途离开去做其余事情,通过sendMessage发音信给领导,领导思想了片刻,同意之后,通过Looper.looep()方法将音讯回传给自身,说本人得以相差,然后笔者就调用handleMessage方法去做别的事情去了。

注:面试的时候,假设只是从字面包车型客车角度来表明Handler、Looper
MessageQueue之间的关系,并不可见真的打动面试官,倒不比再举二个生动的例子,让面试官觉得你是懂面向对象的研讨的。

 

伍、跟线程相关的Handler,即HandlerThread(源码角度解析)

其壹标题得以看一下那篇博客:

http://blog.csdn.net/lmj623565791/article/details/47079737

 

六、主线程往子线程发新闻:(调查你是还是不是确实领会Handler机制)

  我们在平时开支的长河中,日常是子线程往主线程中发音讯,让主线程更新UI。可是依据实际的品种要求,也大概会必要让你在主线程中往子线程中发音讯。

 1 import android.app.Activity;
 2 import android.os.Bundle;
 3 import android.os.Handler;
 4 import android.os.Looper;
 5 import android.os.Message;
 6 import android.util.Log;
 7 import android.view.View;
 8 import android.view.View.OnClickListener;
 9 import android.widget.Button;
10 import android.widget.TextView;
11 
12 public class MainActivity extends Activity implements OnClickListener {
13     public static final int UPDATE_TEXT = 1;
14     private TextView tv;
15     private Button btn;
16     private Handler handler;
17 
18     @Override
19     protected void onCreate(Bundle savedInstanceState) {
20         super.onCreate(savedInstanceState);
21         setContentView(R.layout.activity_main);
22         tv = (TextView) findViewById(R.id.tv);
23         btn = (Button) findViewById(R.id.btn);
24         btn.setOnClickListener(this);
25         //疑问:为什么这段代码如果写在onClick方法里面会报空指针?
26         new Thread(new Runnable() {
27             @Override
28             public void run() {
29                 //1、准备Looper对象
30                 Looper.prepare();
31                 //2、在子线程中创建Handler
32                 handler = new Handler() {
33                     @Override
34                     public void handleMessage(Message msg) {
35                         super.handleMessage(msg);
36                         Log.i("handleMessage:", Thread.currentThread().getName());
37                         Log.i("后台输出", "收到了消息对象");
38                     }
39                 };
40                 //3、调用Looper的loop()方法,取出消息对象
41                 Looper.loop();
42             }
43         }).start();
44 
45     }
46     @Override
47     public void onClick(View v) {
48         Log.i("onClick:", Thread.currentThread().getName());
49         switch (v.getId()) {
50             case R.id.btn:
51                 Message msg = handler.obtainMessage();
52                 handler.sendMessage(msg);
53                 break;
54 
55             default:
56                 break;
57         }
58     }
59 }

下边的第3九行至四壹行代码:那是MainThread中发送音讯,在子线程中接收音讯的定势写法。上边包车型客车八个步骤再重新一下:

  • 准备Looper对象
  • 在WorkerThread其中生成三个Handler对象
  • 调用Looper的loop()方法之后,Looper对象将四处地从新闻队列个中取出对象,然后调用handler的handleMessage()方法,处理该音信对象;若是新闻队列中从未对象,则该线程阻塞

留意,此时handleMessage()方法是在子线程中运转的。

后台运维作效果果:

必赢棋牌app官网 7

小小地总计一下:

  首先实施Looper的prepare()方法,这几个主意有三个功能:一是生成Looper对象,而是把Looper对象和当下线程对象形成键值对(线程为键),存放在ThreadLocal个中,然后生成handler对象,调用Looper的myLooper()方法,获得与Handler所对应的Looper对象,那样的话,handler、looper
、音讯队列就形成了各类对应的关系,然后实施下边包车型大巴第伍个步骤,即Looper在音信队列当中循环的取多少。

别的,在本文最初阶的率先段中,大家在主线程中创制Handler也未尝调用Looper.prepare()方法,为啥就未有崩溃呢?,那是出于在先后运营的时候,系统已经帮大家机关调用了Looper.prepare()方法。查看ActivityThread中的main()方法,代码如下所示:

 1 public static void main(String[] args) {  
 2     SamplingProfilerIntegration.start();  
 3     CloseGuard.setEnabled(false);  
 4     Environment.initForCurrentUser();  
 5     EventLogger.setReporter(new EventLoggingReporter());  
 6     Process.setArgV0("<pre-initialized>");  
 7     Looper.prepareMainLooper();  
 8     ActivityThread thread = new ActivityThread();  
 9     thread.attach(false);  
10     if (sMainThreadHandler == null) {  
11         sMainThreadHandler = thread.getHandler();  
12     }  
13     AsyncTask.init();  
14     if (false) {  
15         Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));  
16     }  
17     Looper.loop();  
18     throw new RuntimeException("Main thread loop unexpectedly exited");  
19 }  

 上方代码中,能够看出,在第拾行调用了Looper.prepareMainLooper()方法,而这一个方法又会再去调用Looper.prepare()方法,代码如下所示:

1 public static final void prepareMainLooper() {  
2     prepare();  
3     setMainLooper(myLooper());  
4     if (Process.supportsProcesses()) {  
5         myLooper().mQueue.mQuitAllowed = false;  
6     }  
7 } 

 总计:这样核心就将Handler的创办进程完全搞精晓了,总计一下正是在主线程中能够直接创设Handler对象,而在子线程中需求先调用Looper.prepare()才能成立Handler对象。

 

6、为何在有点时候子线程中是能够直接更新UI的:

那道面试题应该是本文中最难的二个面试题了,要求优异精通。为了回应那个题材,我们供给先通过看源码去探听下边那多少个难题:

(一)Android是什么检查评定非UI线程去更新UI的

(2)ViewRootImp是什么?

(3)ViewRootImp是在哪个地方创立的?

源码小编就不贴出来了,那里笔者只是总括一下。

答案:

  非UI线程真的无法更新UI吗?
是能够的

解释:

  在线程中更新UI时会调用ViewParent.invalidateChild()方法检查当前的thread是还是不是是Mainthread

切切实实源码如下:

1 final ViewParent p = mParent;
2     if (p != null && ai != null && l < r && t < b) {
3     final Rect damage = ai.mTmpInvalRect;
4     damage.set(l, t, r, b);
5     p.invalidateChild(this, damage);
6 }

 而ViewParent是一个接口类,其实现类是ViewRootImpl,通过查阅invalidateChild()方法里面包车型客车代码就足以见见会他调用checkThread()方法。checkThread()方法如下:

1 void checkThread() {
2     if (mThread != Thread.currentThread()) {   //检查更新UI的线程是否是MainThread
3         throw new CalledFromWrongThreadException(
4         "Only the original thread that created a view hierarchy can touch its views.");
5     }
6 }

 上边的第02行正是检查:在线程中更新UI时当前线程是还是不是是MainThread。

但是,ViewRootImpl这么些类是在activity的onResume()方法中开创的。就算在子线程中更新UI,只要在ViewRootImpl成立此前更新UI(比如,程序在执行onCreate方法时,小编就去履行setText方法区更新UI),就能够规避掉checkThread()的检查。

至于本题,给出以下链接大家去细读一下源码吧:

Android更新Ui进阶精解(一):

http://www.jianshu.com/p/6de0a42a44d6

干什么我们能够在非UI线程中更新UI:

http://blog.csdn.net/aigestudio/article/details/43449123

 

自个儿的万众号

下图是本人的微信公众号(生命团队id:vitateam),欢迎有心人关怀。新浪分享技术,公众号分享心智

作者会很谢谢第一群关怀本人的人。那会儿,年轻的自小编和你,环堵萧然;而后,富裕的你和笔者,满载而归。

必赢棋牌app官网 8

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注