当应用程序启动,创建了一个叫“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的方法就行了

UI线程异常处理方法的更多相关文章

  1. OkHttp3几个简单的例子和在子线程更新UI线程的方法

    okHttp用于android的http请求.据说很厉害,我们来一起尝尝鲜.但是使用okHttp也会有一些小坑,后面会讲到如何掉进坑里并爬出来. 首先需要了解一点,这里说的UI线程和主线程是一回事儿. ...

  2. java线程异常处理方法

    工作中常发现有些程序发生异常但却没有错误日志,原因就是一些开发线程异常处理错误,导致程序报错但异常信息打印到堆栈上,不好在生产环境中定位问题. 在java多线程程序中,所有线程都不允许抛出未捕获的ch ...

  3. android在其他线程中访问UI线程的方法

    1.Activity.runOnUiThread( Runnable ) 2.View.post( Runnable ) 3.View.postDelayed( Runnable, long ) 4. ...

  4. Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面

    Android应用的开发过程中需要把繁重的任务(IO,网络连接等)放到其他线程中异步执行,达到不阻塞UI的效果. 下面将由浅入深介绍Android进行异步处理的实现方法和系统底层的实现原理. 本文介绍 ...

  5. Android异步处理系列文章四篇之一使用Thread+Handler实现非UI线程更新UI界面

    目录: Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面Android异步处理二:使用AsyncTask异步更新UI界面Android异步处理三:Handler+L ...

  6. 关于 SWT 的UI线程和非UI线程

    要理解UI线程,先要了解一下“消息循环”这个概念.链接是百度百科上的条目,简单地说,操作系统把用户界面上的每个操作都转化成为对应的消息,加入消息队列.然后把消息转发给对应的应用程序(一般来说,就是活动 ...

  7. 【插件式框架探索系列】使用多UI线程提升性能

    了解WPF线程模型的都知道,UI线程负责呈现和管理UI,而UI元素(派生自 DispatcherObject)只能由创建该元素的线程来访问,这就导致了一些耗时的UI操作将影 响到整个应用程序性能,未响 ...

  8. Android子线程更新UI主线程方法之Handler

    背景: 我们开发应用程序的时候,处于线程安全的原因子线程通常是不能直接更新主线程(UI线程)中的UI元素的,那么在Android开发中有几种方法解决这个问题,其中方法之一就是利用Handler处理的. ...

  9. WPF / Win Form:多线程去修改或访问UI线程数据的方法( winform 跨线程访问UI控件 )

    WPF:谈谈各种多线程去修改或访问UI线程数据的方法http://www.cnblogs.com/mgen/archive/2012/03/10/2389509.html 子线程非法访问UI线程的数据 ...

随机推荐

  1. HTML5之Canvas画正方形

    HTML5之Canvas画正方形 1.设计源码 <!DOCTYPE html> <head> <meta charset="utf-8" /> ...

  2. 提取DirectShow中视频采集的数据

    DirectShow中,数据流(Data Flow)都是依次流过各个Filter的.它对数据的管理也有自己的方法,而且并没有向用户提供一个统一的接口,供用户操作数据流.这里以提取视频采集在的每帧为位图 ...

  3. .Net Core使用Redis的一个入门简单Demo

    本例子讲述一个在.Net core环境中对Redis数据库进行增删改查操作. 首先,要安装好Redis数据库,至于怎么安装,本文不再赘述,可以自行百度,有很详细的教程. 安装好之后,在CMD中输入 r ...

  4. UML类图10分钟快速入门

    虚线箭头指向依赖: 实线箭头指向关联: 虚线三角指向接口: 实线三角指向父类: 空心菱形能分离而独立存在,是聚合: 实心菱形精密关联不可分,是组合: 原文作者:圣杰 原文地址:http://www.j ...

  5. C#接口--C#基础

    1.接口的声明 接口:描述属于任何类或者结构的一组相关功能,是一种规范.功能 组成:属性.方法.事件.索引或者这四种成员的任意组合构成 基本知识点: 1)接口默认的权限修饰符是:public,不允许加 ...

  6. 第十篇:Map/Reduce 工作机制分析 - 数据的流向分析

    前言 在MapReduce程序中,待处理的数据最开始是放在HDFS上的,这点无异议. 接下来,数据被会被送往一个个Map节点中去,这也无异议. 下面问题来了:数据在被Map节点处理完后,再何去何从呢? ...

  7. angular 按下回车键触发事件

    angularJs  按下回车键触发事件这个功能很简单,但是今天的却让我掉坑很久.... 由于我的页面上有两个不同方法都传$event事件,如search($event)和create($event) ...

  8. 华为悦盒 EC6108V9U 破解过程全记录(root扫盲) [原创]

    电信宽带送的 IPTV 盒子,CPU 为 Hi3798M,1G 内存,8G 存储,支持 H.265 硬解码,系统为 Android 4.4.2,却只能看电视,岂不浪费?好在华为厚道,还是留了后门供 D ...

  9. 初探WebSocket

    初探WebSocket node websocket socket.io 我们平常开发的大部分web页面都是主动'拉'的形式,如果需要更新页面内容,则需要"刷新"一个,但Slack ...

  10. rpm 相关问题

    specfies multiple packages 错误 这是安装了多个相同的rpm包,所以无法卸载,可以加上--allmatches rpm -e xxx.rpm --allmatches err ...