Handler机制详细解析请参考参考
android中handler的一些总结以及使用(一)之handler的基本用法
android中handler的一些总结以及使用(二)之handle使用时用到的几个主要方法介绍
android中handler的一些总结以及使用(三)之HandleThread的使用
Handler简介
Handler是Android中引入的一种让开发者参与处理线程中消息循环的机制,可以用来在多线程间进行通信,典型案例就是在另一个线程中更新UI界面。
说到handler就不得不说Looper和MessageQueue,handler主要作用是发送消息(message)和处理消息,MessageQueue的作用是存储handler发送过来的Message,Looper顾名思义,就是不断地循环消息队列(MessageQueue),取出消息,交给handler执行。handler在初始化的时候会去绑定Looper,一个线程只能一个Looper,一个Looper中也只有一个MessageQueue,三者相互协同共同完成任务,缺一不可。
handler的使用
每次你新创建一个Handle对象,它会绑定于创建它的线程(也就是UI线程)以及该线程的消息队列,Handler可以把一个Message对象或者Runnable对象压入到消息队列中,进而在UI线程中获取Message或者执行Runnable对象,Handler把压入消息队列有两类方式
handler的基本用法
(1)主线程与子线程之间的通信
public class HandlerTest extends AppCompatActivity {
private static final String TAG = "HandlerTest";
private Message mMessage;
// new 一个handler实例,覆写 handleMessage()方法,用于处理消息
private Handler mHandle = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){ //根据msg.what区分是消息类型
case 0:
Log.d(TAG,"handleMessage of type 0"); // 根据不同消息类型,写出具体的处理方式
case 1:
Log.d(TAG,"handleMessage of type 1");
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_test);
new Thread(new Runnable() {
@Override
public void run() {
// 首先需要创建message对象,有以下三种方式
// 1、 new Message()
mMessage = new Message();
// 2、调用Message类的静态方法 (推荐使用)
mMessage = Message.obtain();
// 3、调用handler类的方法(此方法是调用Message.obtain(Handler h)方法去创建Message对象)
mMessage = mHandle.obtainMessage();
mMessage.what = 0; // 不同的what值,用于区分不同的消息类型
// 发送消息到MessageQueue
mHandle.sendMessage(mMessage);
}
}).start();
}
}
(2)子线程与子线程之间的通信
前面说handler初始化时需要绑定Looper,上面的例子中我们并没有绑定写Looper,为什么也可以呢?
是因为我们的应用在启动时,ActivityManager会去创建ActivityThread,用以维护Activity生命周期。ActivityThread中的main()方法应用的入口,在main()方法中,会去创建一个Looper对象,存储在线程的ThreadLocal对象中,handler在初始化时,会从ThreadLocal对象中去读取当前线程的Looper,所以才不需要我们手动去创建一个Looper。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_test);
final Thread Thread1 = new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare(); // 创建一个Looper对象
mHandle = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG,"handleMessage in Child Thread");
}
};
Looper.loop(); // 开始循环消息队列
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
Log.d(TAG,"enter send handleMessage");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
mHandle.sendEmptyMessageDelayed(1,5000);
}
});
Thread1.start();
thread2.start();
}
}
thread2发送消息到thread1中的handler,实现子线程与子线程间的通信。
(3)handler发送消息的方法
1、sendMessage 立即发送信息
2、sendEmptyMessage 立即发送空消息
3、sendMessageDelayed 指定延时多少毫秒后发送信息
4、sendEmptyMessageDelayed 指定延时多少毫秒后发送空信息
5、sendMessageAtTime 指定在什么时间发送消息
6、sendEmptyMessageAtTime 指定在什么时间发送空消息
7、post 立即发送信息
8、postAtTime 指定在什么时间发送消息
9、postDelayed 指定延时多少毫秒后发送信息
以上9个方法实际上最终都是调用sendMessageAtTime方法,让我们看看两个典型的方法sendMessage和post
sendMessage方法源码:
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0); //调用sendMessageDelay方法
}
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); //调用sendMessageAtTime方法
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
post方法源码:
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0); //最终也是调用sendMessageAtTime
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain(); //创建一个message对象,上一节讲message获取的几种方式时,我们也有提到过
m.callback = r; //将此Runable对象保存在message的callback变量上
return m;
}
可以看出最后都是调用了sendMessageAtTime方法,最后再调用enqueueMessage
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; //message的target属性保存着发送此消息的handler,建立了两者的对应关系
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis); //保存消息到队列中
}
handler发送消息后,该消息保存到消息队列中,上面我们提到过,loop方法会不断循环消息队列取出消息,然后交给目标handler(也就是message的target属性对应的handler,从这看一个队列是可以被多个handler共享的,但是一个handler只能绑定一个队列)处理。
android 中更新UI的几种方式
常见的大概有四种:runOnUiThread、handler.post、handler.sendMessage、view.post
public class FiveActivity extends Activity {
// 只是在布局布置一个 TextView
private TextView textView;
// 通过Handler来更新一下UI
Handler handler = new Handler() {
// 实现一下Handler里面的handleMessage方法
public void handleMessage(android.os.Message msg) {
// 第二个方法是从外边拿到数据然后返回到里面
textView.setText("第二种方法handlerEmptyMessags");
}
};
/**
* 第一方法 Handler post
*/
public void handler1() {
handler.post(new Runnable() {
@Override
public void run() {
// 这里弄个文本消息
textView.setText("第一种方法Handler post");
}
});
}
/**
* 第二种方法 sendEmptyMessage
*/
public void handler2() {
handler.sendEmptyMessage(1);
}
/**
* 第三种方法 runOnUiThread
*/
public void handler3() {
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText("第三个方方法runOnUiThread");
}
});
}
/**
* 第四种方法view
* post----它会判断当前是不是UI线程,默认情况下,会通过Handler.post发送一个action。如果是UI线程的话执行run()方法
*/
public void handler4() {
textView.post(new Runnable() {
@Override
public void run() {
textView.setText("第四种方法 view post");
}
});
}
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
// 将布局,引用到这个类---因为为了方便我弄多了一个类
setContentView(R.layout.five);
// 找到ID
textView = (TextView) findViewById(R.id.textview);
// 更新UI 创建一个线程,后台处理。
new Thread() {
// 实现线程Thread 中的run方法
public void run() {
try {
//休息两秒后再执行,因为本地网络速递较快,为了看效果。如果网络的话就去掉
Thread.sleep(2000);
// handler1();
// handler2();
// handler3();
handler4();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
};
}.start();
}
}
总结:常见的四种方式更新UI都差不多,都是通过Handler来更新,只是代码上的本质而已。