面试时,很多面试官都喜欢采用这种方法,来考察求职者的能力

本文主要是介绍面试时,很多面试官都喜欢采用这种方法,来考察求职者的能力,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

面试时,很多面试官都喜欢采用这种方法,来考察求职者的能力,基础是否扎实。(循环渐进法)这个知识点,80%的求职者很容易陷入面试官精心设计的陷阱这篇文章就是关于Activity生命周期的一个陷阱,就是一个很好的例子。


今天我们来聊一聊另一个话题:非UI主线程能不能操作UI?


进入话题前,先来看一下这段代码,这段代码的大意是尝试在Thread中更新一个Button的文字。或许你听了会很惊讶,在Thread中更新一个Button的状态,这怎么可能?不急,我们先来看看。

 1 public class MainActivity extends AppCompatActivity {
2 private Button btn;
3 @Override
4 protected void onCreate(Bundle savedInstanceState) {
5 super.onCreate(savedInstanceState);
6 setContentView(R.layout.activity_main);
7     initView();
8}
9private void initView() {
10  btn = (Button) findViewById(R.id.bt_start);
11  btn.setOnClickListener(this);
12  newThead();
13}
14private void newThead() {
15  new Thread() {
16    @Override
17    public void run() {
18        super.run();
19        btn.setText("update");
20     }
21    }.start();
22  }
23}



编译运行了,可以正常更改按钮的文字。这是为什么,开发文档不是明确地指出吗?

Do not access the Android UI toolkit from outside the UI thread


确实,把代码稍微加上这么一句

 1   private void newThead() {
2   new Thread() {
3     @Override
4     public void run() {
5    super.run();
6         try {
7              Thread.sleep(1000);
8         } catch (InterruptedException e) {
9          e.printStackTrace();
10      }
11     btn.setText("update");
12   }
13  }.start();
14 }
15}


编译运行,出现


 1 android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
2                                                                      at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6556)
3                                                                      at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:942)
4                                                                      at android.view.ViewGroup.invalidateChild(ViewGroup.java:5081)
5                                                                      at android.view.View.invalidateInternal(View.java:12713)
6                                                                      at android.view.View.invalidate(View.java:12677)
7                                                                      at android.view.View.invalidate(View.java:12661)
8                                                                      at android.widget.TextView.checkForRelayout(TextView.java:7159)
9                                                                      at android.widget.TextView.setText(TextView.java:4342)
10                                                                      at android.widget.TextView.setText(TextView.java:4199)
11                                                                      at android.widget.TextView.setText(TextView.java:4174)
12                                                                      at com.aikaifa.splashview.activity.MainActivity$1$override.run(MainActivity.java:59)
13                                                                      at com.aikaifa.splashview.activity.MainActivity$1$override.access$dispatch(MainActivity.java)
14                                                                      at com.aikaifa.splashview.activity.MainActivity$1.run(MainActivity.java:0)

下面,我们再把代码稍微改一下,增加一个onClick事件看看:

 1 public class MainActivity extends AppCompatActivity implements View.OnClickListener {
2 private Button btn;
3 @Override
4 protected void onCreate(Bundle savedInstanceState) {
5 super.onCreate(savedInstanceState);
6 setContentView(R.layout.activity_main);
7     initView();
8}
9private void initView() {
10  btn = (Button) findViewById(R.id.bt_start);
11  btn.setOnClickListener(this);
12}
13@Override
14public void onClick(View view) {
15switch (view.getId()) {
16    case R.id.bt_start:
17        newThead();
18        break;
19  }
20}
21private void newThead() {
22  new Thread() {
23    @Override
24    public void run() {
25        super.run();
26        btn.setText("update");
27     }
28    }.start();
29  }
30}


等程序运行完毕,我们点击一下按钮,在onClick的时候crash了。这是什么情况,在onCreate的时候执行不会crash,在按钮下执行就crash了。


我们来看一下错误日志:


640?wx_fmt=png


日志说不能在非UI线程中去更新UI控件。我们跟进源码中去查找一下ViewRootImpl.java这个文件。看看怎么一回事,找到这个异常:


1void checkThread() {  
2    if (mThread != Thread.currentThread()) {  
3        throw new CalledFromWrongThreadException("Only the original thread that created a view hierarchy can touch its views.");  
5    }  
6}


判断更新UI控件的时候是否在UI线程中进行,如果不是的话就会crash。也就是onCreate的时候这个判断并没有被执行到,所以onCreate中启动的Thread并不会导致程序的crash。


而在按钮点击下,这个判断执行到了。


虽然第一种情况不会出现crash异常,但建议大家不要这样做,这样很容易导致UI阻塞,如果非要更改,我们可以借助Activity.runOnUiThread,View.Post来实现,这也是google推荐的。


1 /*
2 * IMPLEMENTATION
3 */

4  private void checkThread() {
5  if (started && !isFxApplicationThread()) {
6    throw new IllegalStateException("Task must only be  used from the FX Application Thread");
7 }
8}



640?wx_fmt=png


 1public class MainActivity extends AppCompatActivity   implements View.OnClickListener {
2 private Button btn;
3 @Override
4 protected void onCreate(Bundle savedInstanceState) {
5super.onCreate(savedInstanceState);
6setContentView(R.layout.activity_main);
7initView();
8 }
9 private void initView() {;
10btn = (Button) findViewById(R.id.bt_start);
11btn.setOnClickListener(this);
12}
13@Override
14public void onClick(View view) {
15switch (view.getId()) {
16    case R.id.bt_start:
17        newThead();
18        break;
19   }
20 }
21 private void newThead() {
22  new Thread() {
23    @Override
24    public void run() {
25        super.run();
26          Looper.prepare();
27          addView();
28          Looper.loop();
29    }
30  }.start();
31}
32private void addView(){
33TextView tx = new TextView(MainActivity.this);
34tx.setText("update");
35tx.setBackgroundColor(ContextCompat.getColor(this,R.color.colorPrimary));
36tx.setGravity(Gravity.CENTER);
37WindowManager wm = MainActivity.this.getWindowManager();
38WindowManager.LayoutParams params = new WindowManager.LayoutParams(
39        200, 200, 200, 200, WindowManager.LayoutParams.FIRST_SUB_WINDOW,
40        WindowManager.LayoutParams.TYPE_TOAST, PixelFormat.OPAQUE);
41wm.addView(tx, params);
42 }
43}

每次刷新UI的时候,会用ViewRootImpl.checkThread()来检验线程是否是View的创建线程。


[END]


今天就分享到此,希望对你有帮助,感谢阅读,感谢有你。

640?wx_fmt=jpeg


阅读推荐:


从事程序员的8大好处,怪不得很多女孩子都喜欢嫁给程序员


这篇关于面试时,很多面试官都喜欢采用这种方法,来考察求职者的能力的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/306491

相关文章

数据库面试必备之MySQL中的乐观锁与悲观锁

《数据库面试必备之MySQL中的乐观锁与悲观锁》:本文主要介绍数据库面试必备之MySQL中乐观锁与悲观锁的相关资料,乐观锁适用于读多写少的场景,通过版本号检查避免冲突,而悲观锁适用于写多读少且对数... 目录一、引言二、乐观锁(一)原理(二)应用场景(三)示例代码三、悲观锁(一)原理(二)应用场景(三)示例

Python列表去重的4种核心方法与实战指南详解

《Python列表去重的4种核心方法与实战指南详解》在Python开发中,处理列表数据时经常需要去除重复元素,本文将详细介绍4种最实用的列表去重方法,有需要的小伙伴可以根据自己的需要进行选择... 目录方法1:集合(set)去重法(最快速)方法2:顺序遍历法(保持顺序)方法3:副本删除法(原地修改)方法4:

Python中判断对象是否为空的方法

《Python中判断对象是否为空的方法》在Python开发中,判断对象是否为“空”是高频操作,但看似简单的需求却暗藏玄机,从None到空容器,从零值到自定义对象的“假值”状态,不同场景下的“空”需要精... 目录一、python中的“空”值体系二、精准判定方法对比三、常见误区解析四、进阶处理技巧五、性能优化

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

如何将Python彻底卸载的三种方法

《如何将Python彻底卸载的三种方法》通常我们在一些软件的使用上有碰壁,第一反应就是卸载重装,所以有小伙伴就问我Python怎么卸载才能彻底卸载干净,今天这篇文章,小编就来教大家如何彻底卸载Pyth... 目录软件卸载①方法:②方法:③方法:清理相关文件夹软件卸载①方法:首先,在安装python时,下

电脑死机无反应怎么强制重启? 一文读懂方法及注意事项

《电脑死机无反应怎么强制重启?一文读懂方法及注意事项》在日常使用电脑的过程中,我们难免会遇到电脑无法正常启动的情况,本文将详细介绍几种常见的电脑强制开机方法,并探讨在强制开机后应注意的事项,以及如何... 在日常生活和工作中,我们经常会遇到电脑突然无反应的情况,这时候强制重启就成了解决问题的“救命稻草”。那

kali linux 无法登录root的问题及解决方法

《kalilinux无法登录root的问题及解决方法》:本文主要介绍kalilinux无法登录root的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,... 目录kali linux 无法登录root1、问题描述1.1、本地登录root1.2、ssh远程登录root2、

SpringMVC获取请求参数的方法

《SpringMVC获取请求参数的方法》:本文主要介绍SpringMVC获取请求参数的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下... 目录1、通过ServletAPI获取2、通过控制器方法的形参获取请求参数3、@RequestParam4、@

Python中的魔术方法__new__详解

《Python中的魔术方法__new__详解》:本文主要介绍Python中的魔术方法__new__的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、核心意义与机制1.1 构造过程原理1.2 与 __init__ 对比二、核心功能解析2.1 核心能力2.2

Python Transformer 库安装配置及使用方法

《PythonTransformer库安装配置及使用方法》HuggingFaceTransformers是自然语言处理(NLP)领域最流行的开源库之一,支持基于Transformer架构的预训练模... 目录python 中的 Transformer 库及使用方法一、库的概述二、安装与配置三、基础使用:Pi