一、Handler消息传递机制的产生原因
出于对性能优化的考虑,致使Android不是线程安全的。如果多个线程并发操作UI组件,会产生线程安全问题。为此,Android制定了一个规则:只允许在UI线程中操作UI组件。但是,试想一下,如果我们创建了一个子线程,在子线程中执行了一个任务,这个任务涉及到要操作UI组件,但由于规则的限制,我们不能直接在子线程中操作UI组件。就在这种情况下,我们的Handler消息传递机制应运而生了。通过它,我们可以发送消息来更新UI线程中的UI组件
二、Handler类简介
Hanlder有两个主要作用:
1、在新启动的线程中发送消息
2、在UI线程中接收并处理消息
三、Handler消息传递机制的工作原理
为了更好的理解Handler的工作原理,我们得先来了解一下与Handler一起工作的几个组件。
1、Message:Handler发送、接受并处理的消息对象
2、Looper:每个线程只能有一个Looper对象。它的Loop方法负责从MessageQueue循环读取Messsage对象,并将读取的Message对象交给发送该消息的Handler处理
3、MessageQueue:消息队列,用来存放Message对象的,采用先进先出的方式来管理Message对象。程序创建Looper对象时会在他的构造器中创建MessageQueue对 象。Looper提供的构造器源代码如下:
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
该构造器使用了private修饰,表明程序员无法通过构造器创建Looper对象。从上面代码不难看出,程序在初始化Looper时会创建一个与之关联的MessageQueue,这个MessageQueue就负责管理消息。
各个组件之间的关系如下图所示
四、Looper对象的分类情况
第一种情况:主UI线程中,系统已经初始化了一个Looper对象,因此程序直接创建Handler即可,然后就可通过Handler来发送消息、处理消息。
第二种情况:程序员自己启动的子线程,程序员必须自己创建一个Looper对象,并启动它。创建Looper对象调用它的prepare()方法即可。然后调用Looper的静态loop()方法来启动它。
五、使用Handler的步骤
第一种情况的步骤就不说了,下面是一个显示当前时间的一个栗子,代码如下:
package com.river.test.handlerdemo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
private TextView mTextView;
public static final int MSG = 0;
Timer mTimer = new Timer();
private Handler myHandler = new Handler(){
@Override public void handleMessage(Message msg) {
if(msg.what==MSG) {
Log.d("TAG", msg.obj.toString());
mTextView.setText( msg.obj.toString());
}
}
};
TimerTask mTask = new TimerTask() {
@Override public void run() {
long time = System.currentTimeMillis();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date(time);
String timeStr= simpleDateFormat.format(date);
Message message = new Message();
message.what = MSG;
message.obj = timeStr;
myHandler.sendMessage(message);
}
};
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.looper_layout);
mTextView = (TextView) findViewById(R.id.tv_show);
mTimer.schedule(mTask,1000,1000);
}
@Override protected void onStop() {
super.onStop();
mTask.cancel();
mTimer.cancel();
}
}
程序运行结果如下图:
第二种情况的使用步骤:
1、调用Looper的prepare()方法为当前线程创建Looper对象,创建Looper对象时,它的构造器会创建与之配套的MessageQueue。
2、有了Looper之后,创建Handler子类的实例,重写handleMessage()方法,该方法负责处理来自于其他线程的消息。
3、调用Looper的loop()方法启动Looper。
下面的栗子与上面不同的是:handler是在子线程上创建的,具体不同看如下代码示例:
package com.river.test.handlerdemo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class LooperActivity extends AppCompatActivity {
private Handler myHandler;
private Button startBtn;
public static final int MSG = 0;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.looper_layout);
startBtn = (Button) findViewById(R.id.btn_start);
startBtn.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
String name = "Hello,World";
myHandler.obtainMessage(MSG,name).sendToTarget();
}
});
new MyThread().start();
}
class MyThread extends Thread{
@Override public void run() {
Looper.prepare();//初始化Looper
myHandler = new Handler(){//绑定handler到MyThread实例的Looper对象
@Override public void handleMessage(Message msg) {//重写Handler处理消息的方法
if(msg.what==MSG) {
Log.d("TAG",msg.obj.toString());
}
}
};
Looper.loop();//启动消息循环
}
}
}
输出结果如下图:
参考书籍《疯狂Android讲义》
本博客只做学习记录和分享交流,不做他用,如有侵权请联系博主删除。