Android中非UI线程不能更新Activity中的组件,但是在开发中经常需要更新UI组件中的属性值,于是Android提供了一套Handler消息传递的机制,handler即可以发送消息,也可以处理消息。
实际上Handler只是封装了消息的发送,Handler是通过Looper来实现消息传递的。
private Looper(){
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
从Looper的构造器可以看出,无法通过Looper()构造器创建Looper对象,在Looper()中,可以看见有一个 MessageQueue(), MessageQueue()实际上是一个消息队列,Handler发送消息时,实际上将消息存储在 MessageQueue()中,发送消息时,Looper会不断从 MessageQueue()中取得消息,交给Handler处理,它采用先进先出的方式进行处理。
创建Looper对象是通过prepare()方法实现,创建Looper的同时也就创建了配套的MessageQueue,下面是Android 中的源码:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
有了Looper对象后,调用loop()方法启动Looper.
以上是Handler进行消息传递的机制,利用Handler就可以更新UI了。
下面是更新UI的四种方法:
package com.example.updateui;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;
//更新UI
public class MainActivity extends Activity {
private TextView textView;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
textView.setText("ok"); //handler2更新UI
}
};
//第一种
private void handler1(){
handler.post(new Runnable() {
@Override
public void run() {
textView.setText("ok");
}
});
}
//第二种
private void handler2(){
handler.sendEmptyMessage(1);
}
//第三种
private void updateUI(){
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText("ok");
}
});
}
//第四种,通过视图直接更新
private void viewUI(){
textView.post(new Runnable() {
@Override
public void run() {
textView.setText("ok");
}
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
new Thread(){
@Override
public void run() {
try {
Thread.sleep(2000);
//handler1();
//handler2();
//updateUI();
viewUI();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
实际上,它们的机制大同小异:
对于post()方法可以从源码中看到:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
对于runOnUiThread()方法
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
它们本质上还是利用Handler机制。
应为每个线程只有一个Looper()对象,所以主线程中已初始化一个Looper()对象, 因此可以直接通过handler发送消息。
若是程序员自己启动子线程,则必须创建一个Looper()对象,下面是一个实例:
/**
*利用Looper更新UI
*/
public class TestLooper extends Activity {
private LooperThread looperThread;
private TextView textView;
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_handler);
textView = (TextView) findViewById(R.id.tv_handler);
imageView = (ImageView)findViewById(R.id.image_handler);
imageView.setImageResource(R.drawable.meimei01);
textView.setText("测试looper");
looperThread = new LooperThread();
looperThread.start();
}
class LooperThread extends Thread{
public Handler handler;
@Override
public void run() {
Looper.prepare();
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what == 0x001){
Toast.makeText(TestLooper.this,msg.getData().getString("looper"),Toast.LENGTH_LONG).show();
// textView.setText(msg.getData().getString("looper"));
}
}
};
Looper.loop();
}
}
public void setMsg( View v){
Message msg = new Message();
msg.what = 0x001;
Bundle bundle = new Bundle();
bundle.putString("looper","hello looper");
msg.setData(bundle);
textView.setText(msg.getData().getString("looper"));
looperThread.handler.sendMessage(msg);
}
}