android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original

运行时报 android.view.ViewRootImpl$CalledFromWrongThreadException:错误

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

原因操作阻塞了UI线程 或者 在工作线程中操作了UI元素

知道原因就好解决了:

在工作线程中更新UI的三种方法:

1. Activity.runOnUiThread(Runnable) ;

2. Handler(sendMessage(Message) or post(Runnable));

3. AsyncTask ;

出现种错误一般是在使用第三方方法时,没有注意是不是UI线程 所导致的!个人比较喜欢 runOnUiThread() 来解决。

当应用程序启动,创建了一个叫“main”的线程,用于管理UI相关,又叫UI线程。其他线程叫工作线程(Work Thread)。

Single Thread Model

  • 一个组件的创建并不会新建一个线程,他们的创建都在UI线程中进行,包括他们的回调方法,如onKeyDown()。
  • 当在UI线程中进行某些耗时的操作时,将会阻塞UI线程,一般阻塞超过5秒就会显示一个ANR对话框。
  • UI线程是非线程安全的,所以,不能在工作线程中操作UI元素。

    两个原则

    • Do not block the UI thread (不要阻塞UI线程)
    • Do not access the Android UI toolkit from outside the UI thread (不要在工作线程中操作UI元素)

    在工作线程更新UI方法

    • Activity.runOnUiThread(Runnable)
    • Handler
      • sendMessage(Message)
      • post(Runnable)
    • AsyncTask

      • execute()
      • doInBackground()
      • onPostExecute()

    例子程序

    • HandlerActivity01

      • 在工作线程中进行UI操作。
    • HandlerActivity02

      • Handler的两个重要方法:sendMessage和post。
    • HandlerActivity03

      • 官方推荐最佳方法。

    HandlerActivity01主要代码:

    Java代码   

    1. btnEnd.setOnClickListener(new View.OnClickListener() {
    2. @Override
    3. public void onClick(View v) {
    4. new Thread(new Runnable() {
    5. @Override
    6. public void run()
    7. {
    8. //在新建的线程(工作线程)中改变Button的文字
    9. btnEnd.setText("Text Changed in Sub Thread");
    10. }
    11. }).start();
    12. }
    13. });

    这是一种错误的做法,运行程序,会报错误:

    Java代码   

    1. android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

    HandlerActivity02主要代码:

    Java代码   

    1. public class HandlerActivity02 extends Activity
    2. {
    3. private int title = 0;
    4. Button btnStart,btnEnd;
    5. private Handler mHandler = new Handler()
    6. {
    7. public void handleMessage(Message msg)
    8. {
    9. //更新UI
    10. switch (msg.what)
    11. {
    12. case 1:
    13. updateTitle();
    14. break;
    15. }
    16. };
    17. };
    18. public void onCreate(Bundle savedInstanceState)
    19. {
    20. super.onCreate(savedInstanceState);
    21. setContentView(R.layout.main);
    22. btnStart = (Button)findViewById(R.id.start);
    23. btnEnd = (Button)findViewById(R.id.end);
    24. //新启动一个线程,进行耗时操作
    25. Timer timer = new Timer();
    26. //每六秒执行一次MyTask的run方法
    27. timer.scheduleAtFixedRate(new MyTask(this), 1, 6000);
    28. }
    29. private class MyTask extends TimerTask
    30. {
    31. private Activity context;
    32. MyTask(Activity context)
    33. {
    34. this.context = context;
    35. }
    36. @Override
    37. public void run()
    38. {
    39. //耗时操作略....
    40. //更新UI方法  1
    41. Message message = new Message();
    42. message.what = 1;
    43. mHandler.sendMessage(message);
    44. //更新UI方法  2
    45. mHandler.post(updateThread);
    46. //更新UI方法  3
    47. context.runOnUiThread(updateThread);
    48. }
    49. }
    50. public void updateTitle()
    51. {
    52. setTitle("Welcome to Mr Wei's blog " + title);
    53. title++;
    54. }
    55. Runnable updateThread = new Runnable()
    56. {
    57. @Override
    58. public void run()
    59. {
    60. //更新UI
    61. btnStart.setText(String.valueOf(title));
    62. btnEnd.setText(String.valueOf(title));
    63. }
    64. };
    65. }

    这里有个容易出错的地方,在更新UI方法2和3中,我们传入的参数是一个Runnable对象,一般认为这就会启动一个新的线程,而且常有人在这个Runnable对象的run方法中进行耗时操作。看过这块的源码就会知道,其实,android只是调用了这个Runnable对象的run方法而已,并没有启动新的线程,而且我们不应该在run方法中进行耗时操作,因为这个run方法最终是在UI线程里面执行的。也就是说,run方法里面只应该放更新UI的代码,handleMessage方法也一样。

    如果你要看这部分源代码的话,相信这个图对你会有帮助:

    HandlerActivity03主要代码:

    Java代码   

    1. public class HandlerActivity03 extends Activity
    2. {
    3. Button btnStart;
    4. @Override
    5. protected void onCreate(Bundle savedInstanceState)
    6. {
    7. // TODO Auto-generated method stub
    8. super.onCreate(savedInstanceState);
    9. setContentView(R.layout.main);
    10. btnStart = (Button)findViewById(R.id.start);
    11. btnStart.setOnClickListener(new View.OnClickListener() {
    12. @Override
    13. public void onClick(View v) {
    14. //开始执行AsyncTask,并传入某些数据
    15. new LongTimeTask().execute("New Text");
    16. }
    17. });
    18. }
    19. private class LongTimeTask extends AsyncTask
    20. {
    21. @Override
    22. protected String doInBackground(String... params)
    23. {
    24. try
    25. {
    26. //线程睡眠5秒,模拟耗时操作,这里面的内容Android系统会自动为你启动一个新的线程执行
    27. Thread.sleep(5000);
    28. }
    29. catch (InterruptedException e)
    30. {
    31. e.printStackTrace();
    32. }
    33. return params[0];
    34. }
    35. @Override
    36. protected void onPostExecute(String result)
    37. {
    38. //更新UI的操作,这里面的内容是在UI线程里面执行的
    39. btnStart.setText(result);
    40. }
    41. }
    42. }

    这个方法确实挺好,因为它为你封装了许多操作,你只需要记住在doInBackground方法中写耗时操作的代码,在onPostExecute方法中写更新UI的方法就行了。

andorid程序UI线程下开启子线程闪退错误解决相关推荐

  1. win10浏览器闪退_Win10系统下Edge浏览器经常闪退的解决方法

    大家都知道win10系统中自带有edge浏览器,不过有时候在使用edge浏览器的时候可能会遇到经常闪退的情况,这是怎么回事呢,针对Win10系统下Edge浏览器经常闪退这个问题,小编这就给大家带来具体 ...

  2. Android开发之可以在任意页面开启主线程和使用线程池开启子线程的工具类

    代码很简单说下思路,只需要使用handler通信即可,点击跳转源码页面链接

  3. Mac环境下百度网盘闪退的解决方法

    转载请注明出处:http://blog.csdn.net/dongdong9223/article/details/126248674 本文出自[我是干勾鱼的博客] Mac的百度网盘本来可以正常使用, ...

  4. Android,UI主线程与子线程

    在一个Android 程序开始运行的时候,会单独启动一个Process.默认的情况下,所有这个程序中的Activity或者Service(Service和 Activity只是Android提供的Co ...

  5. main线程 子线程 顺序_在主线程main中开启子线程thread示例

    主线程中开启子线程代码实例: 创建CancleThread类 继承 Thread,对run()方法进行重写代码实例: class CancleThread extends Thread { priva ...

  6. Android之HandlerThread源码分析和简单使用(主线程和子线程通信、子线程和子线程通信)

    1.先熟悉handler方式实现主线程和子线程互相通信方式,子线程和子线程的通信方式 如果不熟悉或者忘记了,请参考我的这篇博客     Android之用Handler实现主线程和子线程互相通信以及子 ...

  7. pthread_detach():主线程与子线程分离,子线程结束后,资源自动回收

    https://github.com/Rtoax/test/tree/master/c/glibc/pthread 目录 前言 pthread_join() pthread_detach() 前言 1 ...

  8. python线程退出_python子线程退出及线程退出控制的代码

    下面通过代码给大家介绍python子线程退出问题,具体内容如下所示: def thread_func(): while True: #do something #do something #do so ...

  9. selenium 程序执行完之后,Chrome闪退的解决方法

    问题描述:之前用selenium下的webdriver打开chrome网页后,网页会一直留在页面,但是昨天突然浏览器运行完后,自己就退出了. 现象如下面的gif,这个gif有点长,反正就是自己会闪退: ...

最新文章

  1. 手机充值接口 php,首信易支付,话费充值接口
  2. 前NASA工程师硬核“复仇”,自制闪光臭屁炸弹,把快递小偷都整不会了
  3. SVN的搭建及使用(三)用TortoiseSVN修改文件,添加文件,删除文件,以及如何解决冲突,重新设置用户名和密码等...
  4. 台湾大学林轩田机器学习基石课程学习笔记14 -- Regularization
  5. 陈顺志 php,芦芽山之情
  6. 客户端连接mysql 自动断开_MySql连接空闲8小时自动断开的原因及连接池配置方法...
  7. 深度学习logit是什么?
  8. 图片文字美化广告位代码 广告源码
  9. 正式请求:Could you...? May I...? _52
  10. 曝张一鸣在游戏群批员工上班时聊游戏,遭回怼:那你退群啊
  11. Object C学习笔记15-协议(protocol)
  12. CCF201403-3 命令行选项(100分)
  13. ARcore 相关学习
  14. Linux下获取Root权限的方法
  15. 从零搭建Spring Boot脚手架:手写Mybatis通用Mapper4
  16. 转载:asm volatile GCC的内嵌汇编语法 ATT汇编语言语法
  17. Mac 上的 iOS App 可用性(IOS APP availability on Mac)
  18. 港大黄凯斌:6G时代的边缘智能,香农与图灵的相遇
  19. 技术员常用的工具晨枫U盘维护工具V2.0版
  20. 【前端】CSS(十一)PC端品优购项目(下)

热门文章

  1. 农村信用社招聘考试计算机,农村信用社招聘考试题:计算机(一)
  2. 计算机与人力资源管理论文,计算机专业毕业论文-人力资源管理系统的研究与实现...
  3. Java面试面向对象三大特征,Java面试经典基础问答三
  4. pkl格式数据 训练集_Detectron2训练自己的数据集手把手指导
  5. 漫画 | 苦逼项目是如何诞生的?
  6. 快讯|MIT遥控机器人;日本推出带摄像头的智能AI马桶;德国在线零售商Zalando引进拣货机器人等...
  7. 这种制作PCB板的方法,只需要一分钟!
  8. 监听 html dom 变化,如何监听页面 DOM 变动并高效响应
  9. 新闻发布系统类图_如何熟悉一个系统?(内含知识大图)
  10. 生日快乐程序_祝肖战1005生日快乐-用R给他画个蛋糕爱心吧