同步自:http://www.elitor.org/?p=201
为什么使用Handler?如何使用Handler?
一个Android程序启动的时候中对应的都有一个主线程Main Thread,也就是UI线程,用于直观显示。当你的程序功能比较复杂,有的时候需要启动别的线程来运行辅助完成一些功能,但是在这些子线程中是不能直接更新UI线程的,否则会抛出一个ViewRootSCalledFromWrongThreadException异常。所以,我们一般的操作是在这个子线程中处理一些事情,处理完了,通过Handler给主线程发送一个message(调用sendMessage()函数完成),而在主线程中将会自动调用handleMessage(Message msg)来处理(没有没什么,这就是Handler的功能),事实上Handler类的这个handleMessage是一个空函数,里面什么事情也没干,查看android的reference便知,所以我们需要自己定义一个类继承Handler,然后override这个函数。
总结:
1.需要自己定义一个类继承Handler类,并且override它的handleMessage(Message)函数,可以在这个函数里面实现自己UI的更新等主线程需要的操作。
2.在子线程中通过Handler对象的sendMessage(Message)函数来发送消息给主线程,一旦执行完这个函数,主线程将会自动调用handleMessage(Message)进行操作。
写一个例子:
package org.elitor;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class HandlerActivity extends Activity
{
private Button btn = null;
private MyHandler myHandler = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
Log.d("Thread", "Main Thread...");
System.out.println("Main Thread: ThreadID---" + Thread.currentThread().getId());
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn = (Button)findViewById(R.id.btn);
myHandler = new MyHandler();
btn.setText("OK");
btn.setOnClickListener(new MyBtnClick());
}
//定义一个MyHandler类继承Handler,override其handleMessage(Message)函数
class MyHandler extends Handler
{
@Override
public void handleMessage(Message msg)
{
// TODO Auto-generated method stub
super.handleMessage(msg);
//打印调试信息
Log.d("Thread", "MyHandler handleMessage...");
System.out.println("MyHandler : ThreadID---" + Thread.currentThread().getId());
btn.setText("handler");
btn.setOnClickListener(new MyBtnClick());
}
}
//定义一个内部线程类MyThread,实现Runnable接口
class MyThread implements Runnable
{
@Override
public void run()
{
// TODO Auto-generated method stub
Log.d("Thread", "MyThread handleMessage...");
System.out.println("MyThread at: ThreadID---" + Thread.currentThread().getId());
//下面四句可以理解为封装一个消息
Message msg = new Message();
Bundle b = new Bundle();
b.putString("value1", "test");
msg.setData(b);
//封装完消息之后,可以通过Handler的对象开始向主线程发送这些消息了
myHandler.sendMessage(msg);
}
}
//还定义一个监听器类,用于监听Button按下事件,实现OnClickListener接口即可
class MyBtnClick implements OnClickListener
{
//一旦绑定Button,如果有click事件将会执行onClick函数
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
Log.d("BtnClick", "MyButton Clicked...");
//可以在点击Button的时候启动线程
MyThread m = new MyThread();
new Thread(m).start();
}
}
}
点击btn的时候将启动线程,在线程里通过handler发送一个消息,主线程通过handleMessage(Message)函数来更新UI,例子中哦给简单的更改了btn的名字。另在例子中加入了几个Log,通过Log我们可以看出handleMessage(Message)函数确实和主线程处于同一线程中,而子线程在别的线程中。