您的位置:首页 > 移动开发 > Android开发

【Android基础知识】Handler、Message、Looper的关系

2016-07-12 17:56 513 查看

为什么只能在UI线程进行更新UI

最根本的目的就是为了解决多线程并发问题。

  假如在一个Activity中,有多个线程去更新UI,并且都没有加锁,那么会产生什么问题?

更新界面错乱

  如果对更新UI的操作都进行加锁处理的话又会产生什么问题?

性能下降

为了处理上面的问题,android给我们提供了一套更新UI的handler机制,我们不用关心多线程问题,只需要去遵循这样的机制就可以了。

 

Handler的基本概念

提供了异步的线程处理。

有很多的操作不能放在onCreate里面,如下载操作等耗时比较长的操作。我们把这些操作放在一些单独的线程里面。

Android 更新UI

错误的更新方式:

在非UI线程中更新UI

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myText = (TextView)findViewById(R.id.text);
new Thread(){
@Override
public void run() {
try {
Thread.sleep(2000);
myText.setText("hello android");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
}



正确的使用方式,使用handler

Handler.post()方法直接执行了线程的run()方法,其实这个线程和Activity在同一个线程中。并没有调用start方法,没有启动新线程。

public class MainActivity extends Activity {
private TextView myText ;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myText = (TextView)findViewById(R.id.text);
new Thread(){
@Override
public void run() {
//这里使用post方法后这个线程是运行在UI线程中的
handler.post(new Runnable() {

@Override
public void run() {
try {
Thread.sleep(2000);
myText.setText("hello android");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}.start();
}
}

使用Callback对message进行拦截

需要引入包import android.os.Handler.Callback;

//handler Callback 方法,可以对message进行拦截,如果返回true则拦截
private Handler handler2 = new Handler(new Callback() {
//这个方法可以对接收到的message进行拦截
@Override
public boolean handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "1", Toast.LENGTH_SHORT).show();
return false;
}
}){
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "2", Toast.LENGTH_SHORT).show();
}
};

在UI线程创建Handler

UI线程默认会创建一个Looper,Handler在调用构造方法的时候会默认去关联这个Looper对象,所以在主线程中创建一个Handler的方法是
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
}
};

在子线程创建Handler

子线程中没有Looper对象,所以我们要自己去获取一个Loopoer对象,并且需要调用Looper.loop()方法,轮循处理消息。
public class LooperThread extends Thread {
@Override
public void run() {
// 将当前线程初始化为Looper线程
//当前线程里就产生了一个Looper对象,在创建Handler的时候会和其关联起来
Looper.prepare();

// ...其他处理,如实例化handler

// 开始循环处理消息队列,这是一个死循环,有消息就处理,没有消息就阻塞
Looper.loop();
}
}

Android 消息处理机制: Handler   Message   Looper

一 Handler封装了消息的发送,(主要包括消息发送给谁,一般发送给自己)

Looper

1.内部包含一个消息队列也就是MessageQueue,所有的Handler发送的消息都走向消息队列。

2.Looper.Loop()方法,就是一个死循环,不断从MessageQueue取消息,如果有消息就处理,没有消息就阻塞。

二 MessageQueue ,就是一个消息队列,可以添加消息,并处理消息。

三 Handler也很简单,内部会跟Looper进行关联,也就是说在Handler的内部可以找到Looper,找到了Looper也就找到了MessageQueue,在Handler发送消息时其实是向MessageQueue队列中发送消息。

总结:handler负责发送消息,Looper负责接收Handler发送的消息,并把消息发送给handler自己,MessageQueue就是一个存储消息的容器。

Handler发送消息
有了handler之后,我们就可以使用
post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable,long),sendEmptyMessage(int),sendMessage(Message), sendMessageAtTime(Message, long)和
sendMessageDelayed(Message, long)这些方法向MQ上发送消息了。光看这些API你可能会觉得handler能发两种消息,一种是Runnable对象,一种是message对象,这是直观的理解,但其实post发出的Runnable对象最后都被封装成message对象了。

1 message.target为该handler对象,这确保了looper执行到该message时能找到处理它的handler,即loop()方法中的关键代码。

 

Handler处理消息

// 处理消息,该方法由looper调用
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 如果message设置了callback,即runnable消息,处理callback!
handleCallback(msg);
} else {
// 如果handler本身设置了callback,则执行callback
if (mCallback != null) {
/* 这种方法允许让activity等来实现Handler.Callback接口,避免了自己编写handler重写handleMessage方法。
if (mCallback.handleMessage(msg)) {
return;
}
}
// 如果message没有callback,则调用handler的钩子方法handleMessage
handleMessage(msg);
}
}

// 处理runnable消息
private final void handleCallback(Message message) {
message.callback.run(); //直接调用run方法!
}
// 由子类实现的钩子方法
public void handleMessage(Message msg) {
}

HandlerThread的使用

注意:Handler属于哪个线程不是看它在哪里创建的,而是看其关联的Looper对象在哪个线程

实现子线程向主线程互相发送消息,子线程中可以处理耗时任务
/*
* 如何向子线程发送消息
*/
public class FourthActivity extends Activity implements OnClickListener{
private Button sendButton;
private Button stopButton;

private HandlerThread thread;
private Handler threadHandler;
//创建一个和主线程相关的handler
private Handler handler = new Handler(){
@Override
public void handleMessage(android.os.Message msg) {
//给子线程发送一个消息
Message message = new Message();
message.what =1;//这里需要设置和removeMessage方法中的参数一致,不然停止不了
threadHandler.sendMessageDelayed(message, 1000);
Log.i("meng","main handler");
}
};
@Override
public void onCreate(android.os.Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.four);
sendButton = (Button)findViewById(R.id.send_message);
stopButton = (Button)findViewById(R.id.stop_message);
sendButton.setOnClickListener(this);
stopButton.setOnClickListener(this);
thread = new HandlerThread("handler thread");
thread.start();
//创建一个子线程的handler
threadHandler = new Handler(thread.getLooper()){
@Override
public void handleMessage(android.os.Message msg) {
Message message = new Message();
message.what = 1;
//每隔1秒给主线程发送一个消息
handler.sendMessageDelayed(message, 1000);
Log.i("meng","thread handler");
}
};
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.send_message:
//调用
handler.sendEmptyMessage(1);
break;
case R.id.stop_message:
handler.removeMessages(1);
break;
default:
break;
}
}
}
精彩博客链接: http://blog.csdn.net/lmj623565791/article/details/47079737/
http://blog.csdn.net/lmj623565791/article/details/38377229
http://blog.csdn.net/lmj623565791/article/details/38476887
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息