Handler


对android开发了解多一些的开发者应该都知道handler在android中的重要性。
Android中的消息机制是针对某一个具体线程的。一个线程只能有一个looper,通过looper来不停取出消息队列中的消息。
在默认创建的线程中是不具备消息队列消息循环的,如果想让其被这些功能,需要调用Looper.prepare()绑定Looper实例,调用Looper.loop()进入消息循环
非UI线程如何与UI线程通信部分我们看出UI线程中有两个原则:
1.不要阻塞ui线程
2.不要在非ui线程修改ui线程元素
那么问题来了:在子线程中进行耗时操作后如何将通知ui线程更新数据呢?这就是handler机制的主要用途。
官方文档给出的用途有两个:
1.在ui线程未来的某个时间点调度message和runnables(postAtTime,postDelay,sendMessageAtTime等);
2.让一个action在另一个子线程中运行(子线程中执行耗时操作,完成之后通知UI thread更新)。

6.1 常见用法
先介绍一下与之配合使用的几个重要概念:
6.1.1 Message和Message队列
message是一个可以包含描述和任意类型数据对象的类,可以将Message发送给handler进行处理。下面从代码角度来分析一下:
1.它实现了Parcelable接口,可以用于系统之间传递数据: public final class Message implements Parcelable;
2.比较中要的成员变量:Handler target(处理该message的handler),Runnable callback(定义runnable,主要作用是将Runnable可以封装成message对象来处理,后面有分析),pubic int what(指明消息类型,使用较多),,public Object obj(可以是的任意对象);
3 如何创建message对象:虽然提供了public 构造方法,但是建议使用Message.obtain()或者Message.obtain(Message)。因为内部使用了message池,避免了过多的创建message对象。上源码:
  1. //Return a new Message instance from the global pool. Allows us to avoid allocating new objects in many cases.  
  2.     public static Message obtain() {  
  3.         synchronized (sPoolSync) {  
  4.             if (sPool != null) {  
  5.                 Message m = sPool;  
  6.                 sPool = m.next;  
  7.                 m.next = null;  
  8.                 sPoolSize--;  
  9.                 return m;  
  10.             }  
  11.         }  
  12.         return new Message();  
  13.     }  
//Return a new Message instance from the global pool. Allows us to avoid allocating new objects in many cases.
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

它还重载了很多方法,都是调用obtain来实现的如:public static Message obtain(Message)
  1. /** 
  2.    * Same as {@link #obtain()}, but copies the values of an existing message (including its target) into the new one. 
  3.    * @param orig Original message to copy. 
  4.    * @return A Message object from the global pool. 
  5.    */  
  6.   public static Message obtain(Message orig) {  
  7.       Message m = obtain();  
  8.       m.what = orig.what;  
  9.       m.arg1 = orig.arg1;  
  10.       m.arg2 = orig.arg2;  
  11.       m.obj = orig.obj;  
  12.       m.replyTo = orig.replyTo;  
  13.       if (orig.data != null) {  
  14.           m.data = new Bundle(orig.data);  
  15.       }  
  16.       m.target = orig.target;  
  17.       m.callback = orig.callback;  
  18.   
  19.       return m;  
  20.   }  
  /**
     * Same as {@link #obtain()}, but copies the values of an existing message (including its target) into the new one.
     * @param orig Original message to copy.
     * @return A Message object from the global pool.
     */
    public static Message obtain(Message orig) {
        Message m = obtain();
        m.what = orig.what;
        m.arg1 = orig.arg1;
        m.arg2 = orig.arg2;
        m.obj = orig.obj;
        m.replyTo = orig.replyTo;
        if (orig.data != null) {
            m.data = new Bundle(orig.data);
        }
        m.target = orig.target;
        m.callback = orig.callback;

        return m;
    }

再看看如果回收:
  1. // Return a Message instance to the global pool.  You MUST NOT touch the Message after calling this function -- it has effectively been freed.  
  2.       public void recycle() {  
  3.        clearForRecycle();  
  4.        synchronized (sPoolSync) {  
  5.            if (sPoolSize < MAX_POOL_SIZE) {  
  6.                next = sPool;  
  7.                sPool = this;  
  8.                sPoolSize++;  
  9.            }  
  10.        }  
  11.    }   
 // Return a Message instance to the global pool.  You MUST NOT touch the Message after calling this function -- it has effectively been freed.
       public void recycle() {
        clearForRecycle();
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    } 

4.sentToTarget函数:
  1. public void setTarget(Handler target) {  
  2.        this.target = target;  
  3.    }  
 public void setTarget(Handler target) {
        this.target = target;
    }
实际上就是设置自己的成员变量target

MessageQueue顾名思义就是Message队列
着重分析两个函数
enqueueMessage(Message msg,long when)
  1. final boolean enqueueMessage(Message msg, long when) {  
  2.         ...  
  3.         final boolean needWake;  
  4.         synchronized (this) {  
  5.             msg.when = when;  
  6.             //Log.d("MessageQueue", "Enqueing: " + msg);  
  7.             Message p = mMessages;  
  8.             if (p == null || when == 0 || when < p.when) {  
  9.                 msg.next = p;  
  10.                 mMessages = msg;  
  11.                 needWake = mBlocked; // new head, might need to wake up  
  12.             } else {  
  13.                 Message prev = null;  
  14.                 while (p != null && p.when <= when) {  
  15.                     prev = p;  
  16.                     p = p.next;  
  17.                 }  
  18.                 msg.next = prev.next;  
  19.                 prev.next = msg;  
  20.                 needWake = false// 按照顺序排列,时间小的排在队首  
  21.             }  
  22.         }  
  23.         if (needWake) {  
  24.             nativeWake(mPtr);  
  25.         }  
  26.         return true;  
  27.     }  
final boolean enqueueMessage(Message msg, long when) {
        ...
        final boolean needWake;
        synchronized (this) {
            msg.when = when;
            //Log.d("MessageQueue", "Enqueing: " + msg);
            Message p = mMessages;
            if (p == null || when == 0 || when < p.when) {
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked; // new head, might need to wake up
            } else {
                Message prev = null;
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
                msg.next = prev.next;
                prev.next = msg;
                needWake = false; // 按照顺序排列,时间小的排在队首
            }
        }
        if (needWake) {
            nativeWake(mPtr);
        }
        return true;
    }
可以看出队列是按照时间前后顺序的,时间小的在队首。

next()从队列中取出来一个message
  1. final Message next() {  
  2.        for (;;) {//不停循环取数据  
  3.             ...  
  4.             nativePollOnce(mPtr, nextPollTimeoutMillis);  
  5.             synchronized (this) {  
  6.                 // Try to retrieve the next message.  Return if found.  
  7.                 final long now = SystemClock.uptimeMillis();  
  8.                 final Message msg = mMessages;  
  9.                 if (msg != null) {  
  10.                     final long when = msg.when;  
  11.                     if (now >= when) {//如果时间该message已经到了到执行时间  
  12.                         mBlocked = false;//不阻塞  
  13.                         mMessages = msg.next;//队尾指向下一个  
  14.                         msg.next = null;//标记正在使用  
  15.                         if (false) Log.v("MessageQueue""Returning message: " + msg);  
  16.                         msg.markInUse();  
  17.                         return msg;  
  18.                     } else {  
  19.                         nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);//下一次pool时间间隔,native层调用  
  20.                     }  
  21.                 } else {  
  22.                     nextPollTimeoutMillis = -1;  
  23.                 }          
  24.         ...  
  25.         }  
  26.     }  
final Message next() {
       for (;;) {//不停循环取数据
            ...
            nativePollOnce(mPtr, nextPollTimeoutMillis);
            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                final Message msg = mMessages;
                if (msg != null) {
                    final long when = msg.when;
                    if (now >= when) {//如果时间该message已经到了到执行时间
                        mBlocked = false;//不阻塞
                        mMessages = msg.next;//队尾指向下一个
                        msg.next = null;//标记正在使用
                        if (false) Log.v("MessageQueue", "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    } else {
                        nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);//下一次pool时间间隔,native层调用
                    }
                } else {
                    nextPollTimeoutMillis = -1;
                }        
		...
        }
    }

6.1.2 Runnable
实际可以看成是message。看看Handler中是如何处理的post(Runnable)
  1. public final boolean post(Runnable r)  
  2.     {  
  3.        return  sendMessageDelayed(getPostMessage(r), 0);  
  4.     }  
public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
调用的是处理message的方法,再看getPostMessage(Runnable):
  1. private final Message getPostMessage(Runnable r) {  
  2.         Message m = Message.obtain();  
  3.         m.callback = r;  
  4.         return m;//仍然是作为一个Message对象来处理  
  5.     }  
private final Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;//仍然是作为一个Message对象来处理
    }
尼玛,真省事,就是将Runnable包装到message中,作为该message一个成员变量,实际上还是作为一个Message对象来处理。

6.1.3 Looper 
不断的将messageQueue中的信息取出来执行
重要的变量:     
1. static final ThreadLocal<Looper> sThreadLocal;用来存放和线程相关的信息。也就是将线程和Looper绑定到一起。
2. final MessageQueue mQueue 要操作的消息队列。也就是一个looper对应一个messageQuene
重要方法:
1 public static void prepare:  
  1. /** Initialize the current thread as a looper. This gives you a chance to create handlers that then reference this looper, before actually starting the loop. Be sure to call {@link #loop()} after calling this method, and end it by               */calling {@link #quit()}.       
  2.   public static void prepare() {  
  3.       if (sThreadLocal.get() != null) {  
  4.           throw new RuntimeException("Only one Looper may be created per thread");  
  5.       }  
  6.       sThreadLocal.set(new Looper());  
  7.   }  
  /** Initialize the current thread as a looper. This gives you a chance to create handlers that then reference this looper, before actually starting the loop. Be sure to call {@link #loop()} after calling this method, and end it by             	 */calling {@link #quit()}.     
    public static void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }
就是将Thread 和looper进行绑定。可以看出一个线程有且只能有一个looper。在和线程进行绑定时调用了Looper的构造方法Looper()构造了一个Looper实例:
  1. private Looper() {  
  2.         mQueue = new MessageQueue();  
  3.         mRun = true;  
  4.         mThread = Thread.currentThread();  
  5.     }  
private Looper() {
        mQueue = new MessageQueue();
        mRun = true;
        mThread = Thread.currentThread();
    }
初始化messagequeue,将当前线程赋值给looper对象mThread变量。
再看looper()函数:

public static void loop() 
  1. public static void loop() {  
  2.         //先判断是否绑定了looper,如果该线程没有绑定Looper对象,则提示应该先调用prepare方法。  
  3.         Looper me = myLooper();  
  4.         if (me == null ) {  
  5.             throw new RuntimeException( "No Looper; Looper.prepare() wasn't called on this thread.");  
  6.         }  
  7.           
  8.         MessageQueue queue = me. mQueue;         
  9.         while (true ) {  
  10.             //从queue中取message并进行分发message  
  11.             Message msg = queue.next(); // might block  
  12.             if (msg != null ) {  
  13.                 if (msg.target == null) {  
  14.                     // No target is a magic identifier for the quit message.  
  15.                     return ;  
  16.                 }             
  17.                 //分发message  
  18.                 msg.target.dispatchMessage(msg);      
  19.                //回收  
  20.                 msg.recycle();  
  21.             }  
  22.         }  
  23.     }  
public static void loop() {
        //先判断是否绑定了looper,如果该线程没有绑定Looper对象,则提示应该先调用prepare方法。
        Looper me = myLooper();
        if (me == null ) {
            throw new RuntimeException( "No Looper; Looper.prepare() wasn't called on this thread.");
        }
        
        MessageQueue queue = me. mQueue;       
        while (true ) {
            //从queue中取message并进行分发message
            Message msg = queue.next(); // might block
            if (msg != null ) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return ;
                }           
                //分发message
                msg.target.dispatchMessage(msg);    
               //回收
                msg.recycle();
            }
        }
    }
先看myLooper():就是返回线程所绑定的looper实例,可以看出如果没有绑定则报错。
再看dispatchMessage(msg)这个方法实际是Handler类中定义的(message中的target对象就是Handler类型)。

public void dispatchMessage(Message msg) 
  1. public void dispatchMessage(Message msg) {  
  2.         if (msg.callback != null) {  
  3.             handleCallback(msg);//如果msg.callback!=null,执行handleCallback(msg)方法,此方法的实现就是:message.callback.run()  
  4.         } else {  
  5.             if (mCallback != null) {  
  6.                 if (mCallback.handleMessage(msg)) {//如果在创建handler时已经执行了callback,这执行该callback的handleMessage方法  
  7.                     return;  
  8.                 }  
  9.             }  
  10.             handleMessage(msg);//msg中没有定义callback(Runnable)时才执行handleMessage方法,我们可以override此方法  
  11.         }  
  12.     }  
public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);//如果msg.callback!=null,执行handleCallback(msg)方法,此方法的实现就是:message.callback.run()
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {//如果在创建handler时已经执行了callback,这执行该callback的handleMessage方法
                    return;
                }
            }
            handleMessage(msg);//msg中没有定义callback(Runnable)时才执行handleMessage方法,我们可以override此方法
        }
    }
其中 mCallback  是Callback类型:
  1. public interface Callback {  
  2.     public boolean hanleMessage(Message msg);  
  3. }  
    public interface Callback {
        public boolean hanleMessage(Message msg);
    }
4 Looper中还有一个重要的方法,这个方法一般不用,但在后面的分析中会涉及到:prepareMainLooper()
我们在主线程中创建looper对象时并没有主动调用prepare方法,是因为这里已经实例化一个mainLooper对象给主线程使用。 

6.1.4 Handler类
handler类的主要作用就是发送和处理message对象的。
先看看有哪些重要的成员变量
1 final Looper mLooper:该线程绑定的Looper实例
2 final MessageQueue mQueue:mLooper中的成员变量
3 final Callback mCallback:自定义handleMessage方法接口
再来看重要的方法
1 构造方法:public Handler(),
  1. public Handler(){  
  2.           //..  
  3.      mLooper=Looper.myLooper();//获得该线程绑定的Looper实例  
  4.      if(mLooper==null){  
  5.           throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");  
  6.      }  
  7.      mQueue = mLooper.mQueue;  
  8.      mCallback=null;  
  9.      }  
public Handler(){
          //..
     mLooper=Looper.myLooper();//获得该线程绑定的Looper实例
     if(mLooper==null){
          throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
     }
     mQueue = mLooper.mQueue;
     mCallback=null;
     }

2 带参数的构造方法:public Handler(Looper,Callback)    
  1. public Handler(Looper looper,Callback callback){  
  2.           mLooper=looper;  
  3.           mQueue = looper.mQueue;  
  4.           mCallback= callback;  
  5.      }  
public Handler(Looper looper,Callback callback){
          mLooper=looper;
          mQueue = looper.mQueue;
          mCallback= callback;
     }

3 发送消息(Runnable实际上也是消息,这里不再分析),有好几种方式,最终都是sendMessageAtTime(Message,Long)   
  1. public boolean sendMessageAtTime(Message msg, long uptimeMillis)  
  2.   {  
  3.       boolean sent = false ;  
  4.       MessageQueue queue = mQueue;  
  5.       if (queue != null) {  
  6.           msg.target = this ;//该message对象的target成员变量设置为此handler实例  
  7.           sent = queue.enqueueMessage(msg, uptimeMillis);//调用messageQueue来讲message加入队列  
  8.       }  
  9.       else {  
  10.           RuntimeException e = new RuntimeException(  
  11.               this + " sendMessageAtTime() called with no mQueue");  
  12.           Log. w("Looper", e.getMessage(), e);  
  13.       }  
  14.       return sent;  
  15.   }      
  public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    {
        boolean sent = false ;
        MessageQueue queue = mQueue;
        if (queue != null) {
            msg.target = this ;//该message对象的target成员变量设置为此handler实例
            sent = queue.enqueueMessage(msg, uptimeMillis);//调用messageQueue来讲message加入队列
        }
        else {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log. w("Looper", e.getMessage(), e);
        }
        return sent;
    }    

4 handleMessage(Message)
根据取出来的message对象进行消息处理,一般override
     
典型用法:
1.子线程中:     
  1. class MyThread extends Thread{  
  2.           public Handler mHanlder;  
  3.           public void run(){  
  4.                //将线程与Looper绑定。  
  5.                //此方法必须在handler创建之前调用,handler否则实例化报错  
  6.                Looper.prepare();  
  7.   
  8.                mHandler = new Handler(){  
  9.                          public void handleMessage(Message msg){  
  10.                          //处理消息  
  11.                          }  
  12.                            
  13.                };       
  14.                  
  15.                //不停的取出该线程中message队列中的消息。  
  16.                Looper.loop();  
  17.           }  
  18.      }  
class MyThread extends Thread{
          public Handler mHanlder;
          public void run(){
               //将线程与Looper绑定。
               //此方法必须在handler创建之前调用,handler否则实例化报错
               Looper.prepare();

               mHandler = new Handler(){
                         public void handleMessage(Message msg){
                         //处理消息
                         }
                         
               };     
               
               //不停的取出该线程中message队列中的消息。
               Looper.loop();
          }
     }

2.主线程中直接实例化Handler,这里简要介绍一个为什么不需要Looper.prepare和Looper.loop.
是因为在程序启动已经做了这些工作,在ActivityThread类中main方法:  
  1. public static void main(String[] args) {  
  2.       Looper.prepareMainLooper();  
  3.       if (sMainThreadHandler == null) {  
  4.           sMainThreadHandler = new Handler();  
  5.       }         
  6.       Looper.loop();        
  7.   }  
  public static void main(String[] args) {
        Looper.prepareMainLooper();
        if (sMainThreadHandler == null) {
            sMainThreadHandler = new Handler();
        }       
        Looper.loop();      
    }
         
6.2 流程分析
下面以一个具体案例来分析怎么调用的:
比如说在子线程中发送一个消息给UI线程
首先UI线程中定义了一个Handler:   
  1. private Handler handler = new Handler(){  
  2.         public void handleMessage(Message msg){  
  3.                   if(msg.what=1){  
  4.                        tv.setText("数据下载完毕");  
  5.                   }  
  6.              }  
  7.    };      
  private Handler handler = new Handler(){
          public void handleMessage(Message msg){
                    if(msg.what=1){
                         tv.setText("数据下载完毕");
                    }
               }
     };    
需要在子线程中执行耗时操作:
  1. new Thread(){  
  2.           public void run(){                      
  3.                try{  
  4.                     //模拟耗时操作  
  5.                     Thread.sleep(10*1000);  
  6.                     //发送消息,通知UI线程更新  
  7.                     handler.sendEmptyMessage(1);  
  8.                 }catch(Exception e){  
  9.               }       
  10.           }  
  11.      }.start();  
new Thread(){
          public void run(){                    
               try{
                    //模拟耗时操作
                    Thread.sleep(10*1000);
                    //发送消息,通知UI线程更新
                    handler.sendEmptyMessage(1);
                }catch(Exception e){
              }     
          }
     }.start();
流程分析:  
1该UI线程中的Looper.prepareMainLooper();和 Looper.loop(); 执行,这样就不需要在实例化handler时调用了prepare和looper。线程中已经有一个looper实例,且已经开始不停的从messageQueue中读取message。
2.子线程中给通过UI线程的handler变量调用handler.sendMessage系类方法,给Ui线程的消息队里发送一个消息。
3.Looper.loop方法调用messageQueue的next()方法取消息,取出来之后调用handler的dispatchMessage方法。
4.执行dispatchMessage方法,由于message中callback ==null,所以执行override的handleMessage方法,更新textview。

版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值