UI线程异常处理方法
当应用程序启动,创建了一个叫“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代码- btnEnd.setOnClickListener(new View.OnClickListener() {
 - @Override
 - public void onClick(View v) {
 - new Thread(new Runnable() {
 - @Override
 - public void run()
 - {
 - //在新建的线程(工作线程)中改变Button的文字
 - btnEnd.setText("Text Changed in Sub Thread");
 - }
 - }).start();
 - }
 - });
 
这是一种错误的做法,运行程序,会报错误:
Java代码- android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
 
HandlerActivity02主要代码:
Java代码- public class HandlerActivity02 extends Activity
 - {
 - private int title = 0;
 - Button btnStart,btnEnd;
 - private Handler mHandler = new Handler()
 - {
 - public void handleMessage(Message msg)
 - {
 - //更新UI
 - switch (msg.what)
 - {
 - case 1:
 - updateTitle();
 - break;
 - }
 - };
 - };
 - public void onCreate(Bundle savedInstanceState)
 - {
 - super.onCreate(savedInstanceState);
 - setContentView(R.layout.main);
 - btnStart = (Button)findViewById(R.id.start);
 - btnEnd = (Button)findViewById(R.id.end);
 - //新启动一个线程,进行耗时操作
 - Timer timer = new Timer();
 - //每六秒执行一次MyTask的run方法
 - timer.scheduleAtFixedRate(new MyTask(this), 1, 6000);
 - }
 - private class MyTask extends TimerTask
 - {
 - private Activity context;
 - MyTask(Activity context)
 - {
 - this.context = context;
 - }
 - @Override
 - public void run()
 - {
 - //耗时操作略....
 - //更新UI方法 1
 - Message message = new Message();
 - message.what = 1;
 - mHandler.sendMessage(message);
 - //更新UI方法 2
 - mHandler.post(updateThread);
 - //更新UI方法 3
 - context.runOnUiThread(updateThread);
 - }
 - }
 - public void updateTitle()
 - {
 - setTitle("Welcome to Mr Wei's blog " + title);
 - title++;
 - }
 - Runnable updateThread = new Runnable()
 - {
 - @Override
 - public void run()
 - {
 - //更新UI
 - btnStart.setText(String.valueOf(title));
 - btnEnd.setText(String.valueOf(title));
 - }
 - };
 - }
 
这里有个容易出错的地方,在更新UI方法2和3中,我们传入的参数是一个Runnable对象,一般认为这就会启动一个新的线程,而且常有人在这个Runnable对象的run方法中进行耗时操作。看过这块的源码就会知道,其实,android只是调用了这个Runnable对象的run方法而已,并没有启动新的线程,而且我们不应该在run方法中进行耗时操作,因为这个run方法最终是在UI线程里面执行的。也就是说,run方法里面只应该放更新UI的代码,handleMessage方法也一样。
如果你要看这部分源代码的话,相信这个图对你会有帮助:

HandlerActivity03主要代码:
Java代码- public class HandlerActivity03 extends Activity
 - {
 - Button btnStart;
 - @Override
 - protected void onCreate(Bundle savedInstanceState)
 - {
 - // TODO Auto-generated method stub
 - super.onCreate(savedInstanceState);
 - setContentView(R.layout.main);
 - btnStart = (Button)findViewById(R.id.start);
 - btnStart.setOnClickListener(new View.OnClickListener() {
 - @Override
 - public void onClick(View v) {
 - //开始执行AsyncTask,并传入某些数据
 - new LongTimeTask().execute("New Text");
 - }
 - });
 - }
 - private class LongTimeTask extends AsyncTask
 - {
 - @Override
 - protected String doInBackground(String... params)
 - {
 - try
 - {
 - //线程睡眠5秒,模拟耗时操作,这里面的内容Android系统会自动为你启动一个新的线程执行
 - Thread.sleep(5000);
 - }
 - catch (InterruptedException e)
 - {
 - e.printStackTrace();
 - }
 - return params[0];
 - }
 - @Override
 - protected void onPostExecute(String result)
 - {
 - //更新UI的操作,这里面的内容是在UI线程里面执行的
 - btnStart.setText(result);
 - }
 - }
 - }
 
这个方法确实挺好,因为它为你封装了许多操作,你只需要记住在doInBackground方法中写耗时操作的代码,在onPostExecute方法中写更新UI的方法就行了
 
UI线程异常处理方法的更多相关文章
- OkHttp3几个简单的例子和在子线程更新UI线程的方法
		
okHttp用于android的http请求.据说很厉害,我们来一起尝尝鲜.但是使用okHttp也会有一些小坑,后面会讲到如何掉进坑里并爬出来. 首先需要了解一点,这里说的UI线程和主线程是一回事儿. ...
 - java线程异常处理方法
		
工作中常发现有些程序发生异常但却没有错误日志,原因就是一些开发线程异常处理错误,导致程序报错但异常信息打印到堆栈上,不好在生产环境中定位问题. 在java多线程程序中,所有线程都不允许抛出未捕获的ch ...
 - android在其他线程中访问UI线程的方法
		
1.Activity.runOnUiThread( Runnable ) 2.View.post( Runnable ) 3.View.postDelayed( Runnable, long ) 4. ...
 - Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面
		
Android应用的开发过程中需要把繁重的任务(IO,网络连接等)放到其他线程中异步执行,达到不阻塞UI的效果. 下面将由浅入深介绍Android进行异步处理的实现方法和系统底层的实现原理. 本文介绍 ...
 - Android异步处理系列文章四篇之一使用Thread+Handler实现非UI线程更新UI界面
		
目录: Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面Android异步处理二:使用AsyncTask异步更新UI界面Android异步处理三:Handler+L ...
 - 关于 SWT 的UI线程和非UI线程
		
要理解UI线程,先要了解一下“消息循环”这个概念.链接是百度百科上的条目,简单地说,操作系统把用户界面上的每个操作都转化成为对应的消息,加入消息队列.然后把消息转发给对应的应用程序(一般来说,就是活动 ...
 - 【插件式框架探索系列】使用多UI线程提升性能
		
了解WPF线程模型的都知道,UI线程负责呈现和管理UI,而UI元素(派生自 DispatcherObject)只能由创建该元素的线程来访问,这就导致了一些耗时的UI操作将影 响到整个应用程序性能,未响 ...
 - Android子线程更新UI主线程方法之Handler
		
背景: 我们开发应用程序的时候,处于线程安全的原因子线程通常是不能直接更新主线程(UI线程)中的UI元素的,那么在Android开发中有几种方法解决这个问题,其中方法之一就是利用Handler处理的. ...
 - WPF / Win Form:多线程去修改或访问UI线程数据的方法( winform 跨线程访问UI控件 )
		
WPF:谈谈各种多线程去修改或访问UI线程数据的方法http://www.cnblogs.com/mgen/archive/2012/03/10/2389509.html 子线程非法访问UI线程的数据 ...
 
随机推荐
- 个性化WinPE封装方法 ----最后实战“制作WinPE3.0图文教程”
			
经过前几讲,主要目的就是准备一些"原材料",熟悉一些"命令",实际上是"战前演练准备".下面要进入"实战状态",成败在此 ...
 - Struts2实现文件上传(一)
			
Struts2实现文件上传 文件上传成功后结果页面 result.jsp: <%@ page language="java" import="java.util.* ...
 - linux下insmod lsmod rmmod
			
insmod(install module) 功能说明:载入模块 install loadable kernel module 语法:insmod [-fkmpsvxX][-o <模块名称> ...
 - hdu5860 Death Sequence
			
这题一开始写的线段数是从中间开始查找 k个 导致是nlogn 每次查找应该都是从头找每次找的个数不同就好了 还有一种递推的写法我放下面了 #include<bits/stdc++.h> u ...
 - Java并发系列[7]----CountDownLatch源码分析
			
CountDownLatch(闭锁)是一个很有用的工具类,利用它我们可以拦截一个或多个线程使其在某个条件成熟后再执行.它的内部提供了一个计数器,在构造闭锁时必须指定计数器的初始值,且计数器的初始值必须 ...
 - 【BZOJ1924】【SDOI2010】所驼门王的宝藏(Tarjan,SPFA)
			
题目描述 在宽广的非洲荒漠中,生活着一群勤劳勇敢的羊驼家族.被族人恭称为"先知"的Alpaca L. Sotomon是这个家族的领袖,外人也称其为"所驼门王". ...
 - Vue-路由配置和使用步骤整理
			
介绍 路由:控制组件之间的跳转,不会实现请求.不用页面刷新,直接跳转-切换组件>>> 安装 本地环境安装路由插件vue-router: cnpm install vue-rou ...
 - Health Check - 每天5分钟玩转 Docker 容器技术(142)
			
强大的自愈能力是 Kubernetes 这类容器编排引擎的一个重要特性.自愈的默认实现方式是自动重启发生故障的容器.除此之外,用户还可以利用 Liveness 和 Readiness 探测机制设置更精 ...
 - NancyFX 第三章 Web框架
			
如果使用Nancy作为一个WEB框架而言,会有什么不同?实际上很多. 在使用Nancy框架为网页添加Rest节点和路由和之前的Rest框架中是相同的,这方面没有什么需要学习的了.Nancy采用一贯的处 ...
 - three.js引擎基础知识—摄像机、场景及渲染器
			
一.three.js采用右手坐标系: x轴正方向向右,y轴正方向向上,z轴由屏幕从里向外,如下图右: 二.3D编程三要素:场景.渲染器.摄像机 1.场景:创建的物品和模型都需放入场景中 threejs ...