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的方法就行了

java ui线程_UI线程异常处理方法相关推荐

  1. java创建线程的两种方法区别

    在Java中创建一个线程有两种方法:继承Thread类和实现Runnable接口. 下面通过两个例子来分析两者的区别: 1)继承Thread类 public class TestThread exte ...

  2. Java子线程中的异常处理(通用)

    Java子线程中的异常处理(通用) 参考文章: (1)Java子线程中的异常处理(通用) (2)https://www.cnblogs.com/toplist/p/7594557.html 备忘一下.

  3. 求一个简单的java线程代码,Java线程代码的实现方法

    1.继承Thread 声明Thread的子类 运行thread子类的方法 2.创建Thread的匿名子类 3.实现Runnable接口 声明 运行 4.创建实现Runnable接口的匿名类 5.线程名 ...

  4. 【Android NDK 开发】JNI 线程 ( JNI 线程创建 | 线程执行函数 | 非 JNI 方法获取 JNIEnv 与 Java 对象 | 线程获取 JNIEnv | 全局变量设置 )

    文章目录 I . JNI 线程创建 II . 线程执行函数 III . 线程方法获取 Java 对象 IV . 线程方法获取 JNIEnv V . JNI 线程 完整代码示例 I . JNI 线程创建 ...

  5. JVM - 结合代码示例彻底搞懂Java内存区域_线程栈 | 本地方法栈 | 程序计数器

    文章目录 Pre 运行时数据区总览 线程栈 概要 栈内部主要组成部分 局部变量 操作数栈 动态链接 方法出口 小结 程序计数器 本地方法栈 附 测试demo javap JVM字节码指令集手册 Pre ...

  6. java 销毁线程_线程 学习教程(一): Java中终止(销毁)线程的方法

    结束线程有以下三种方法: (1)设置退出标志,使线程正常退出,也就是当run()方法完成后线程终止 (2)使用interrupt()方法中断线程 (3)使用stop方法强行终止线程(不推荐使用,Thr ...

  7. 线程的退出 java_(转)Java结束线程的三种方法

    背景:面试过程中问到结束线程的方法和线程池shutdown shutdownnow区别以及底层的实现,当时答的并不好. 线程属于一次性消耗品,在执行完run()方法之后线程便会正常结束了,线程结束后便 ...

  8. Java和Spring中线程池创建方法

    一.线程池定义 1.JDK中线程池类图 Executor:父接口,所有线程池都实现了这个接口,里面有一个excute()方法用于执行线程 ExecutorService:线程池接口,继承自Execut ...

  9. 停止Java线程,小心interrupt()方法

    转自http://www.blogjava.net/jinfeng_wang/archive/2008/04/27/196477.html 程序是很简易的.然而,在编程人员面前,多线程呈现出了一组新的 ...

最新文章

  1. 树莓派 ubuntu 安装Python+OpenCV
  2. SAP BI工具的优缺点
  3. 如何反复读取同一个 InputStream 对象
  4. 福建职称计算机评聘任,职称聘任工作的有关补充规定(试行)
  5. JS性能分析(测试代码运行时间)
  6. 一个具有Spring Boot,Spring Security和Stormpath的简单Web应用程序-15分钟
  7. Linux终端显示工作路径
  8. Expression Blend 2 September Preview is now available!(中文版)
  9. 不需要英语的计算机行业,北京评职称不再考外语计算机 将涉及300多万人
  10. 3.2生产者和消费者(Producers and Consumers)
  11. LSTM+attention代码原理详解
  12. SpringBoot框架下集成萤石云平台开发海康的摄像头
  13. 有没有一款桌面便签软件,可以手机电脑都能使用的?
  14. PIE-engine 教程 ——使用阈值法加载指定区域的大蒜种植区域并统计其面积
  15. 复习单片机:动态数码管(1 数码管介绍+2 74HC245 和 74HC138 芯片介绍+3 硬件设计+4 软件设计+5 实验现象)
  16. wex5 实战 常用代码模型集合
  17. CSK与KCF算法推导(二)
  18. 阿里云 视频直播 中心推流回调URL
  19. SQLServer SubString函数提示[传递给 LEFT 或 SUBSTRING 函数的长度参数无效]错误的解决方法
  20. Android RecyclerView之代替ListView与GridView

热门文章

  1. Python自动化测试|如何解决前置模块及数据依赖(二)
  2. 【Java】使用前准备工作配置环境变量
  3. Nginx整合tomcat,实现反向代理和负载均衡
  4. 【JAVA学习】09.创建BootstrapTale列表页
  5. 【bzoj3991】[SDOI2015]寻宝游戏 树链的并+STL-set
  6. input readonly 光标显示问题
  7. GL 与 CV 管线 (pipeline) 比较与相互转换
  8. C# 各种字符串格式
  9. 我写的不只是小说更是程序人生
  10. i5 1135g7什么水平_i7-10510U和i5-1135G7对比,该怎么选择呢?