美文网首页
Handler用法总结

Handler用法总结

作者: _人间客 | 来源:发表于2016-07-31 16:31 被阅读412次

    androidsdk:
    一个Handler允许你发送和处理消息(Message)以及与一个线程的消息队列相关的Runnable对象。每个Handler实例都和单个线程以及该线程的消息队列有关。当你创建了一个新Handler,它就会和创建它的线程/消息队列绑定,在那以后,它就会传递消息以及runnable对象给消息队列,然后执行它们。
    需要使用Handler有两大主要的原因:
    (1)在将来的某个时间点调度处理消息和runnable对象;
    (2)将需要执行的操作放到其他线程之中,而不是自己的;

    调度处理消息是通过调用

    post(Runnable), 
    postAtTime(Runnable, long)
    postDelayed(Runnable, long),
    sendEmptyMessage(int),
    sendMessage(Message),
    sendMessageAtTime(Message,long)
    sendMessageDelayed(Message,long)
    

    其中的post版本的方法可以让你将Runnable对象放进消息队列;sendMessage版本的方法可以让你将一个包含有bundle对象的消息对象放进消息队列,然后交由handleMessage(Message)方法处理。(需要复写Handler的handleMessage方法)

    在Android中,规定只能由UI 线程来刷新UI(因为子线程太多,子线程可以刷新UI的话,很容易冲突报错)。Handler在开发中主要用来接收子线程的数据。主线程据此来刷新页面。耗时的操作一般不放在主线程中(否则Android会弹出一个ANR无响应对话框,然后提示按“Force quit”或是“Wait”),而是新建一个Thread子线程,在子线程中完成耗时的操作。即:UI 线程发送命令到子线程,子线程完成命令,并将数据返回给UI线程。

    而若在主线程中实例化一个Handler对象,例如:

    Handler mHandler =  new Handler();
    

    此时并没有新派生一个线程来执行此Handler,而是将此Handler附加在主线程上,因此如果在handler里执行的还是耗时操作,那么Android还是会弹出ANR对话框。

     Handler handler = new Handler(){
    public void run() {     @Override
                public void handleMessage(Message msg) {
                    //Subclasses must implement this to receive messages.
                    super.handleMessage(msg);
                }
            };
    

    使用方法:

    • 默认的Handler(消息处理队列挂在主线程上)
      在onCreate()方法后new handler并写入handler需要执行的语句,在之后的按钮监视器中调用执行。

    • 消息队列仍绑定在主线程上,但在子线程中发送消息。
      new handler并写入handler需要执行的语句,之后新建一个

    Thread workThread = new Thread() {
             public void run() {    
             }
    } 
    

    在该线程中调用handler。这时可以在run方法内做任何耗时的操作,然后将结果以消息形式投递到主线程的消息队列中

    • 将消息队列绑定到子线程上,主线程只管通过Handler往子线程的消息队列中投递消息即可。

    在onCreate方法中声明Looper,并调用mHandler相关方法。

    Looper looper = myLooperThread.getLooper();     
    mHandler = new MyHandler(looper);  
    

    之后写MyHandler类,并重写handleMessage类, 现在在可以执行任何耗时的操作

    class MyHandler extends Handler {     
            public MyHandler(Looper looper) {     
                super(looper);     
            }   
            @Override    
            public void handleMessage(Message msg) {   
    }
    
    • 自己创建新的线程,然后在新线程中创建Looper,主线程调用子线程中的发消息方法,将消息发给子线程的消息队列。

    实现过程

    handler基本使用:new Handler对象,在handleMessage中提供收到消息后相应的处理方法。

    当调用sendEmptyMessage发送一个msg,Message对象被放入一个MessageQueue队列,该队列属于某个Looper对象,每个Looper对象通过ThreadLocal.set(new Looper())同一个Thread绑定。Looper对象所属的线程在Looper.Loop方法中循环执行从MessageQueue队列读取Message对象,并把Message对象交由Handler处理,调用Handler的dispatchMessage方法。
    因此建议在主线程中新建handler。
    如果在自己的线程中新建handler,有时会报错:主线程已经建立一个Looper了,并调用 了Looper.prepareMainLooper(); Looper.loop()。在prepareMainLooper方法中新建了一个looper对象,并与当前进程进行了绑定,而在Looper.loop方法中,线程建立消息循环机制,循环从MessageQueue获取Message对象,调用msg.target.dispatchMessage(msg)。进行处理msg.target在myThreadHandler.sendEmptyMessage(0)设置进去的,因为一个Thead中可以建立多个Hander,通过msg.target保证MessageQueue中的每个msg交由发送message的handler进行处理。
    在新建Handler时需要设置mLooper成员,Looper.myLooper是从当前线程中获取绑定的Looper对象:

    public static final Looper myLooper() {
            return (Looper)sThreadLocal.get();
        }
    

    若Looper对象没有创建,就会抛异常*Can't create handler inside thread that has not called *

    所以我们在一个新线程中要创建一个Handler就需要这样写:
    class MyThread extends Thread {
        public void run() {            
             Log.d(Constant.TAG, 
             MessageFormat.format("Thread[{0}]-- run...",
             Thread .currentThread().getName())); // 其它线程中新建一个handler
             Looper.prepare();
             myThreadHandler = new Handler() { 
                  public void handleMessage(android.os.Message msg) { 
                      Log.d(Constant.TAG, 
                      MessageFormat.format("Thread[{0}]--myThreadHandler handleMessage run...",
                      Thread .currentThread().getName()));           
                      }
             };
            Looper.myLooper().loop();//建立一个消息循环,该线程不会退出                
         }       
    }
    

    Looper.prepare():创建该线程的Looper对象,用于接收消息,在非主线程中是没有looper的所以在创建handler前一定要使用prepare()创建一个Looper

    参考资料:
    http://blog.csdn.net/yuzhiboyi/article/details/7562262
    http://blog.csdn.net/stonecao/article/details/6417364

    相关文章

      网友评论

          本文标题:Handler用法总结

          本文链接:https://www.haomeiwen.com/subject/cratsttx.html