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

来源:互联网 发布:微店如何导入淘宝商品 编辑:程序博客网 时间:2024/05/21 15:07

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

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

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

更新界面错乱

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

性能下降

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

 

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 blocke.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() {@Overridepublic void run() {try {Thread.sleep(2000);myText.setText("hello android");} catch (InterruptedException e) {e.printStackTrace();}}});        }        }.start();    }}

使用Callbackmessage进行拦截

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

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

在UI线程创建Handler

UI线程默认会创建一个Looper,Handler在调用构造方法的时候会默认去关联这个Looper对象,所以在主线程中创建一个Handler的方法是
Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubsuper.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;//创建一个和主线程相关的handlerprivate Handler handler = new Handler(){@Overridepublic void handleMessage(android.os.Message msg) {//给子线程发送一个消息Message message = new Message();message.what =1;//这里需要设置和removeMessage方法中的参数一致,不然停止不了threadHandler.sendMessageDelayed(message, 1000);Log.i("meng","main handler");}};@Overridepublic 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");    }    };}@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch (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







0 0
原创粉丝点击