处女男学Android(二)---Handler预习篇之Android的线程与UI



前言



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;

	@Override
	protected 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() {
			@Override
			public void onClick(View v) {
				// 创建一个WorkerThread并启动
				Thread thread = new MyThread();
				thread.start();
			}
		});
	}

	class MyThread extends Thread {
		@Override
		public void run() {
			try {
				Thread.sleep(3 * 1000); // 休眠3秒来模拟一个耗时任务
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			textView1.setTextColor(Color.RED); // 修改界面上TextView的字体颜色
		}
	}
}


运行程序效果如下:


处女男学Android(二)---Handler预习篇之Android的线程与UI_第1张图片


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


处女男学Android(二)---Handler预习篇之Android的线程与UI_第2张图片


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;

	@Override
	protected 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() {
			@Override
			public void onClick(View v) {
				try {
					Thread.sleep(10 * 1000); // 休眠10秒来模拟一个耗时任务
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				textView1.setTextColor(Color.RED); // 修改界面上TextView的字体颜色
			}
		});
	}
}


运行程序效果如下:


处女男学Android(二)---Handler预习篇之Android的线程与UI_第3张图片


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

XXX is not responding.

Would you like to close it?

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



二、矛盾诞生



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



你可能感兴趣的:(handler)