标签:
今天对Handler 做了一个整体的理解
转一篇园子里的博文 已经写的很详细
本文的思维导图:
众所周知,Handler是Android中用来处理异步的类,为什么有时候可以直接使用子线程,而有时候要使用Handler呢?网上有很多教程讲解Handler,个人认为,很多教程都将Handler复杂化,学会Handler的使用是一件非常简单的事。
我们有这样一个需求,在界面中有一个TextView,当系统启动时,每隔一秒就更改里面的文字为:“当前值: ” + i,其中i是一个变量,每次自增1。要实现这个需求,我们很容易想到如下思路:创建一个子线程,在子线程中定义变量i,进行循环,每次循环中首先 sleep(1000),然后再设置TextView对象的文本,示例代码如下:
1 new Thread() {
2 public void run() {
3 try {
4 for (int i = 0; i < 20; i++) {
5 Thread.sleep(1000);
6 tv.setText("当前的值为: " + i);
7 }
8 } catch (InterruptedException e) {
9 e.printStackTrace();
10 }
11 };
12 }.start();
运行代码,则会在LogCat中出现如下错误:
1 android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
这句话的意思是:只有创建View的线程才可以操作这个View对象。这是什么意思呢?试想一下:当一个Activity中创建了很多个子线程,每个子线程都要修改同一个控件的内容,这时候将会变得混乱。
为了解决这种子线程之间同步互斥的问题,Android的设计人员就规定:创建当前Activity的线程就是主线程,也称为UI线程;只有这个主 线程可以更新界面中的内容。OK!如果子线程也要更新界面中的内容,此时应该怎么处理呢?Android中使用了消息机制。当子线程要对界面UI进行更新 时,要发送一个消息给主线程,主线程中有一个消息队列,消息到达主线程之后便进入消息队列中。主线程通过一个轮循器,检查消息队列中是否有消息,如果有消 息,主线程便会执行这个消息。而这种发送消息、处理消息便封装为一个对象,那就是Handler。
换句话说,子线程负责通过Handler对象的sendMessage()方法发送消息给主线程,而UI更新操作,则是由主线程调用Handler对象的handleMessage()方法来完成。
上面的需求就可以如下实现:
1 public class DemoActivity extends Activity {
2 private TextView tv = null;
3 // 定义Handler对象来发送和处理消息
4 private Handler handler = new Handler() {
5 // 主线程通过这个方法处理消息
6 @Override
7 public void handleMessage(Message msg) {
8 tv.setText("当前的值为:" + msg.obj);
9 }
10 };
11
12 public void onCreate(Bundle savedInstanceState) {
13 super.onCreate(savedInstanceState);
14 setContentView(R.layout.main);
15 tv = (TextView) this.findViewById(R.id.tv);
16 // 创建一个子线程
17 new Thread() {
18 public void run() {
19 try {
20 //子线程中只发送更新UI的消息,不进行更新操作
21 for (int i = 0; i < 20; i++) {
22 Thread.sleep(1000);
23 Message msg = new Message();
24 msg.obj = i;
25 handler.sendMessage(msg);
26 }
27 } catch (InterruptedException e) {
28 e.printStackTrace();
29 }
30 };
31 }.start();
32 }
注意Handler中sendMessage()和handleMessage()两个方法的执行顺序:首先是创建了子线程,然后子线程调用 handler的sendMesssage()方法向主线程发送消息,之后主线程收到消息,调用handler的handleMessage()方法来处 理消息。
模拟下载的进度条:
public class DemoActivity extends Activity {
// 定义进度条的最大值和当前值
private int max = 100;
private int num = 0;
private ProgressBar pb = null;
private TextView tv_progress = null;
private Handler pbHandler = new Handler() {
public void handleMessage(Message msg) {
int num = (Integer) msg.obj;
pb.setProgress(num);
double rate = ((double)num) / max * 100;
String text = "已下载:" + rate + "%";
if (num >= max) {
text = "恭喜你,下载成功!";
}
tv_progress.setText(text);
};
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
pb = (ProgressBar) this.findViewById(R.id.pb);
pb.setMax(max);
tv_progress = (TextView) this.findViewById(R.id.tv_progress);
new MyThread().start();
}
class MyThread extends Thread {
public void run() {
try {
while (num < max) {
Thread.sleep(1000);
num += 5;
Message msg = new Message();
msg.obj = num;
pbHandler.sendMessage(msg);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}
}
布局文件如下:
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="fill_parent"
4 android:layout_height="fill_parent"
5 android:orientation="vertical" >
6 <ProgressBar
7 android:id="@+id/pb"
8 style="?android:attr/progressBarStyleHorizontal"
9 android:layout_width="match_parent"
10 android:layout_height="wrap_content" />
11 <TextView
12 android:id="@+id/tv_progress"
13 android:textSize="20sp"
14 android:layout_width="fill_parent"
15 android:layout_height="wrap_content"
16 android:text="@string/hello" />
17
18 </LinearLayout>
1、 只有主线程才能更新UI;
2、 子线程如果需要更新UI,可以发送消息给主线程,让主线程更新;
3、 Handler可通过sendMessage()发送消息,通过handleMessage()处理消息。
http://www.cnblogs.com/yeahui/archive/2012/11/06/2757799.html
标签:
原文地址:http://www.cnblogs.com/china-xy/p/4482934.html