Android中的handler

来源:互联网 发布:网络电视怎么看中央8吗 编辑:程序博客网 时间:2024/05/16 05:31

首先先看一下android中的线程基本使用方式:

1.      继Thread方式:复写run()方法

2.      实现Runnable方式 接口:传给Thread :new Thread(newplaybackRunnable()).start();

以上两种方法殊归同途,都是在新线程中调用用户实现run方法(方式上还是有区别的,需要可以查看资料,在我的搜藏中也有)。

 

下面我们来关注下android中的hanlder机制。handler主要的用途就是提供一个消息机制,可以方便地在一个消息循环线程中实现消息的处理,无论是在本线程还是在其他线程。不过,首先需要保证线程是有消息循环的。android中的UI线程都是由消息循环的。

 

来看一下handler机制三个相关的类:Handler, Message, Looper

 

 

首先来看下Looper类:它的构造函数是私有的,可见不能在外部创建。唯一创建的地方:

public static void prepare() {       prepare(true);    }

 

private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() != null) {thrownewRuntimeException("Only one Looper may be created per thread");        }sThreadLocal.set(new Looper(quitAllowed));    }

 

此处创建了,就把它设置到ThreadLocal中。

再来看看Looper构造函数都干了什么:

    private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);        mRun = true;        mThread = Thread.currentThread();    }


 它创建了一个消息队列,又结合上面的prepare函数,可见Looper实例在一个Thread中使唯一的,进而消息队列也是唯一的。

 

然后是loop的主循环体:它不停地从消息队列中取出消息来处理。

  public static void loop() {        final Looper me = myLooper();//note how find the Looper         if (me == null) {            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");        }        final MessageQueue queue = me.mQueue;         // Make sure the identity of this thread is that of the local process,        // and keep track of what that identity token actually is.        Binder.clearCallingIdentity();        final long ident = Binder.clearCallingIdentity();         for (;;) {            Message msg = queue.next(); // might block            if (msg == null) {                // No message indicates that the message queue is quitting.                return;            }             // This must be in a local variable, in case a UI event sets the logger            Printer logging = me.mLogging;            if (logging != null) {                logging.println(">>>>> Dispatching to " + msg.target + " " +                        msg.callback + ": " + msg.what);            }             msg.target.dispatchMessage(msg);             if (logging != null) {                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);            }             // Make sure that during the course of dispatching the            // identity of the thread wasn't corrupted.            final long newIdent = Binder.clearCallingIdentity();            if (ident != newIdent) {                Log.wtf(TAG, "Thread identity changed from 0x"                        + Long.toHexString(ident) + " to 0x"                        + Long.toHexString(newIdent) + " while dispatching to "                        + msg.target.getClass().getName() + " "                        + msg.callback + " what=" + msg.what);            }             msg.recycle();        }    }

 

 这里注意消息队列的获得,来看mylooper函数:

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

 

可见,要想消息循环,之前必须要构造出looper实例,并放入到ThreadLocal中。这里,looper已经处理好了,是要调用上面的prepare函数,切忌!

 

然后就是消息如何处理了,可以看到,最主要的就是msg.target.dispatchMessage(msg);这句话,这句就会使你的消息调用handlerdispatchMessage(msg)函数来处理消息了:

    public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }

 

从上就看到了处理消息的三种方式:

1.  调用消息的callback

2.  调用Hanldercallback

3.  调用handlerhandleMessage

 

再来看看Handler

Handler总体来说有两种构造方式:

1.      不带looper的构造方式:

public Handler(Callback callback, boolean async) {        if (FIND_POTENTIAL_LEAKS) {            final Class<? extends Handler> klass = getClass();            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&                    (klass.getModifiers() & Modifier.STATIC) == 0) {                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +                    klass.getCanonicalName());            }        }         mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;        mCallback = callback;        mAsynchronous = async;} }

 

2.      带looper的构造方式:

  public Handler(Looper looper, Callback callback, boolean async) {        mLooper = looper;        mQueue = looper.mQueue;        mCallback = callback;        mAsynchronous = async;}


不带looper的构造方式将获得本线程的Queuelooper的构造方式,获得的是looperQueue.这为之后handler跑在哪个线程上打上了伏笔。

 

最后看看Message

Message的构造大体分为三种:

1.      不带handler和callback的构造:

       public static Message obtain() {        synchronized (sPoolSync) {            if (sPool != null) {                Message m = sPool;                sPool = m.next;                m.next = null;                sPoolSize--;                return m;            }        }        return new Message();}

此时targetnull

 

2.      带参数Handler的构造:

      public static Message obtain(Handler h) {        Message m = obtain();        m.target = h;         return m;    }


此时target为传入的handler

 

3.      带handler和callback的构造:

         public static Message obtain(Handler h, Runnable callback) {        Message m = obtain();        m.target = h;        m.callback = callback;         return m;    }

 

 


有了以上这些基础,我们再来看看消息handler机制是如何使用的:

有几种方式:

1. 直接获取message,然后传给handler处理:

Msg = Message.obtain();Handler.sendMessage(msg);

这里可以跟踪Handler.sendMessage(msg),最后走到:

    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);    }


可以看到,以上将msg入队到自己的queue中,最后就到了queue的线程中去处理了:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);}

注意这里msg.target =this;所以无论消息有没有设置target,只要调用了HandlerSendMessage,它的处理就绑定到了handler上了。

Ok ! 这种方式是跑在handler的线程中的,至于handler值跑在哪个线程中,看看上面handler的两种构造函数就知道了。

 

2. 通过hanlder来获得Message:

class Handler{
public final Message obtainMessage(){     return Message.obtain(this);}
}

可见最后调用的还是消息的obtain(Hanlder)函数。还是在handlerhandleMessage中处理。

 

3. 通过handler的post方式:

  Handler. post(Runnable r):       {       return  sendMessageDelayed(getPostMessage(r), 0);}
    private static Message getPostMessage(Runnable r) {        Message m = Message.obtain();        m.callback = r;        return m;    }


最后还是在handler的线程中,处理的是runnable接口的实现。

 

4. 通过message的SendToTarget的方式:

Message.sendToTarget():       public void sendToTarget() {        target.sendMessage(this);}


可见这个是在与message关联的handler中处理的。注:处理之前message一定要有与之关联的target(Hanlder),也就是message的获得一定通过有handler的方式获得,或者之后要手动设置下handler,不然会因为找不到target而出错。

 

好了,以上4种大概就是我们一般使用handler消息机制的一般方式。

 

 

总结:

1. Looper不用用户操心,但是构造消息循环线程的话,一定要Looper.prepare()一下,以用来创建本地消息队列。

2. handler的两种构造方式决定了handler是在哪个线程上被处理的。 这里要注意:如果hanlder在本地线程上处理,则本地线程一定要有handler机制,也就是消息循环系统。不然handler会因为找不到Looper而出错!

3. Message的获取方式决定了消息的处理是在哪个函数中进行的(参考上面dispatchmessage处理)。 为消息的处理提供了多种方便的方式(参考Message的构造方式一节)。

 

 

最后来看下HandlerThread:

    public void run() {        mTid = Process.myTid();        Looper.prepare();        synchronized (this) {            mLooper = Looper.myLooper();            notifyAll();        }        Process.setThreadPriority(mPriority);        onLooperPrepared();        Looper.loop();        mTid = -1;    }


这个类为我们提供了一个消息循环线程的所有工作,我们只要在这个线程上处理消息就可以了。

调用此类的getLooper可以得到looper,然后用它来构造hanlder就可以发送消息到这个线程来处理了。