前言



Handler是安卓中的一个重要的概念,本篇没有记录Handler的用法,而是为了说明为什么要用Handler,算是学习Handler之前的“预习”吧。



一、Android的线程安全与UI线程



同Java类似,当一个应用程序第一次启动时,Android会同时启动一条主线程(MainThread),主线程主要负责处理与UI相关的事件,主线程通常又称作UI线程。出于性能优化考虑,Android的UI线程并不是线程安全的,这意味着如果有多线程并发操作UI组件,可能会导致线程安全问题。那么为了解决这个问题,Android制定了一条简单的规则:只允许UI线程修改Activity里的UI组件。下面可以通过一个程序的例子来验证一下,功能很简单,大致是这样的:

界面上有一个TextView和一个Button,通过点击Button来修改TextView的字体颜色,当然,这个操作要放到一个新的线程中去,也就是在其他线程中修改UI,看看会不会出错。


Layout代码(activity_main.xml):


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <TextView        android:id="@+id/tv_view1"        android:layout_width="match_parent"        android:layout_height="0dp"        android:layout_weight="1.0"        android:text="@string/hello_world"        android:textSize="20sp"        android:gravity="center_horizontal|center_vertical"/>    <Button        android:id="@+id/btn_changeColor"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="Change Text Color" /></LinearLayout>


Activity代码:


package com.example.handlertest;import android.graphics.Color;import android.os.Bundle;import android.support.v7.app.ActionBarActivity;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class MainActivity extends ActionBarActivity {private TextView textView1;private Button button1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textView1 = (TextView) findViewById(R.id.tv_view1);button1 = (Button) findViewById(R.id.btn_changeColor);button1.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// 创建一个WorkerThread并启动Thread thread = new MyThread();thread.start();}});}class MyThread extends Thread {@Overridepublic void run() {try {Thread.sleep(3 * 1000); // 休眠3秒来模拟一个耗时任务} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}textView1.setTextColor(Color.RED); // 修改界面上TextView的字体颜色}}}


运行程序效果如下:




很明显,程序出错了,那我们看看LogCat下的错误日志:




Only the original thread that created a view hierarchy can touch its views.


这句话的意思显而易见,也验证了Google的做法,也就是说哪个线程创建的UI,哪个线程才有权利去修改这个UI。但是这也并不是针对所有的UI组件,比如ProgressBar就是一个特例,它可以在WorkerThread中修改progress属性的值,在此就不再演示。既然Google不允许我们在WorkerThread里面操作UI,那我们只好放在主线程操作UI了,界面不变,Activity的代码修改如下:


package com.example.handlertest;import android.graphics.Color;import android.os.Bundle;import android.support.v7.app.ActionBarActivity;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class MainActivity extends ActionBarActivity {private TextView textView1;private Button button1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textView1 = (TextView) findViewById(R.id.tv_view1);button1 = (Button) findViewById(R.id.btn_changeColor);button1.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {try {Thread.sleep(10 * 1000); // 休眠10秒来模拟一个耗时任务} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}textView1.setTextColor(Color.RED); // 修改界面上TextView的字体颜色}});}}


运行程序效果如下:




运行结果是显而易见的,程序被阻塞了,Button按下之后无法弹起,用户继续点击之后又弹出了错误窗口:

XXX is not responding.

Would you like to close it?

这个也就是所谓的“ANR”问题,应用程序无法响应,对于焦躁的用户来说,这是及其槽糕和致命的体验。



二、矛盾诞生



通过上面的例子我们发现,既不能在主线程中执行UI操作以及耗时任务,容易被阻塞;同时也不能在其他非UI线程中操作UI,因为操作的结果无法反馈给主线程,那我们应该如何处理?很明显,需要一种机制来解决Android线程之间的通信问题,而正是Handler为我们提供了完整的处理机制和解决方案。



更多相关文章

  1. 由安装Busybox到Android过程中想到的
  2. Android(安卓)修改spinner 字体颜色 样式的方法
  3. Android的线程和线程池
  4. android消息机制
  5. 图解 Android(安卓)Handler 线程消息机制
  6. Android调用webservice
  7. Android的线程和线程池
  8. Android中的Handler在多线程中的使用
  9. Android的单线程模型

随机推荐

  1. android studio基础教程:3.美化按钮
  2. 关于界面布局的一些小知识
  3. Android 自动编译、打包生成apk文件 3 -
  4. ViewStub的使用
  5. 几个Android控件属性笔记
  6. 译:Android(安卓)N不再支持通过Intent传递
  7. Finished with error: ProcessException:
  8. Android(安卓)NDK 错误解决方法(持续更新
  9. 手把手教你搞懂 Android 反编译
  10. Android Studio中如何隐藏顶部状态栏和标