`
ZaneLee007
  • 浏览: 21561 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Android Looper Hander和MessageQueue的关系

阅读更多

       使用Handler和Thread是Android进行线程间通信的主要方式。具体方式是,在异步线程中,使用handler发送Message到指定队列(handler.sendMessage(Message msg))。目标队列接收消息后,将消息添加到队列中,Looper轮询队列,依次对异步线程发送过来的Message进行处理,下面结合Android源码详述。

       先看Handler的构造方法(android.os.Handler.java):

      

 public Handler() {
           //doSomething
          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 = null;
    }

    /**
     * Constructor associates this handler with the queue for the
     * current thread and takes a callback interface in which you can handle
     * messages.
     */
    public Handler(Callback callback) {
       //doSomething
        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;
    }

    /**
     * Use the provided queue instead of the default one.
     */
    public Handler(Looper looper) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = null;
    }

    /**
     * Use the provided queue instead of the default one and take a callback
     * interface in which to handle messages.
     */
    public Handler(Looper looper, Callback callback) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
    }

 每个handler必定有一个对应的Looper,如果没有在构造器中传入,则调用Looper.myLooper()生成一个默认的Looper,再去看Looper的代码(android.os.Looper.java):

 // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static Looper myLooper() {
        return sThreadLocal.get();
    }

 sThreadLocal里什么时候装进去的Looper呢?在android.app.ActivityThread.java代码里发现了对Looper的static方法的调用:

 public static void main(String[] args) {
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();
        if (sMainThreadHandler == null) {
            sMainThreadHandler = new Handler();
        }

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

 这个main方法在系统启动时已经被调用过,android.os.Looper.sThreadLocal是一个静态常量,所有Looper实例共用此常量。

   

     /** 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());
    }

    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare();
        setMainLooper(myLooper());
        myLooper().mQueue.mQuitAllowed = false;
    }

    private synchronized static void setMainLooper(Looper looper) {
        mMainLooper = looper;
    }

    /** Returns the application's main looper, which lives in the main thread of the application.
     */
    public synchronized static Looper getMainLooper() {
        return mMainLooper;
    }

 prepareMainLooper()方法调用了prepare()方法,prepare()方法为android.os.Looper.sThreadLocal进行赋值,我们继续跟进Looper的构造器:

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

 至此,Looper和当前线程对应起来,并且实例化MessageQueue对象。

         按以上,如果我们在主线程里不传Looper实例化了一个Handler,handler对应的Looper所对应的线程就是ActivitThread运行的线程,就是我们常说的主线程。

        如果我们在非主线程里实例化了一个Looper,方法必然是在当前线程调用Looper.prepare(); Looper.loop();。Handler对应的Looper对应当前线程。

        一个线程中可以创建多个Handler,但只能拥有一个Looper,一个Looper对应一个消息队列。

         注:对同一个ThreadLocal对象调用get方法,不同线程将得到不同结果,具体原理与介绍不在此描述。

 

 

 

      下面我们开始使用handler工作,发送消息时使用sendMessage方法或者Message的sendToTarget方法,最终都会调用到handler对应的Looper持有的MessageQueue,队列调用

final boolean enqueueMessage(Message msg, long when) {
        if (msg.isInUse()) {
            throw new AndroidRuntimeException(msg
                    + " This message is already in use.");
        }
        if (msg.target == null && !mQuitAllowed) {
            throw new RuntimeException("Main thread not allowed to quit");
        }
        final boolean needWake;
        synchronized (this) {
            if (mQuiting) {
                RuntimeException e = new RuntimeException(
                    msg.target + " sending message to a Handler on a dead thread");
                Log.w("MessageQueue", e.getMessage(), e);
                return false;
            } else if (msg.target == null) {
                mQuiting = true;
            }

            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; // still waiting on head, no need to wake up
            }
        }
        if (needWake) {
            nativeWake(mPtr);
        }
        return true;
    }

 这个方法把发送的Message添加到队列中,而已经启动的Looper则一直在轮询运行

    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        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();
        
        while (true) {
            Message msg = queue.next(); // might block
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }

                long wallStart = 0;
                long threadStart = 0;

                // 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);
                    wallStart = SystemClock.currentTimeMicro();
                    threadStart = SystemClock.currentThreadTimeMicro();
                }

                msg.target.dispatchMessage(msg);

                if (logging != null) {
                    long wallTime = SystemClock.currentTimeMicro() - wallStart;
                    long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;

                    logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
                    if (logging instanceof Profiler) {
                        ((Profiler) logging).profile(msg, wallStart, wallTime,
                                threadStart, threadTime);
                    }
                }

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

 方法中msg.target.dispatchMessage(msg);说明handlder的dispatchMessage()方法运行在loop()调用的线程中,dispatchMessage方法将调用handleMessage方法。

     这样,Handler处理消息的代码将运行在其对应的Looper所在的线程。整体的结构也就清晰了:

     Handler实例化时,引用一个Looper,Looper唯一对应一个线程,Looper持有一个消息队列,Handler发送消息到消息队列,Looper轮询获取消息队列中的待处理Message,Message对象的target在轮询中顺次分发给Handler,Handler的handleMessage方法被调用。

分享到:
评论

相关推荐

    hander_sy2.rar_android

    5. **MessageQueue和Runnable**: - MessageQueue是消息队列,存储待处理的消息。Looper会从这个队列中取出Message并分发。 - 学习案例可能包含使用`Runnable`配合`postDelayed()`来实现异步操作和延时处理。 6. ...

    个人学习的浅谈handler

    - **消息处理**:`Looper`循环不断地从`MessageQueue`中取出消息,并交给对应的`Handler`对象处理。具体而言,`Looper`通过`dispatchMessage()`方法将消息传递给`Handler`,然后`Handler`通过重写`handleMessage()`...

    Android Handler 机制实现原理分析

    这个过程涉及到多个关键组件的协作,包括ActivityThread、Handler、MessageQueue、Looper和Message,确保UI更新和异步任务的正确同步。理解这一机制对于Android开发者至关重要,因为它允许开发者在不影响UI响应性能...

    handler机制

    4. **处理消息**:Looper不断从MessageQueue中获取消息,并通过Handler对象中的handleMessage()方法来处理消息。这样,就可以在主线程中更新UI或执行其他操作。 ```java @Override public void handleMessage...

    Android Handler 图片浏览器

    Handler负责发送和处理Message,Looper是主线程的消息循环,它不断检查Message Queue是否有新消息,如果有,就分发给相应的Handler处理。 创建一个图片浏览器,我们通常会用到以下技术: 1. **ListView或...

    Android基础网络

    Handler是Android中处理异步消息的关键组件,它与Looper和Message紧密配合工作。Looper是消息循环,它持续检查Message Queue(消息队列),并将消息分发给相应的Handler进行处理。Message是实际携带数据的实体,而...

    Handler方法

    2. **消息队列**:所有发送给`Handler`的消息都会被放入到消息队列(`MessageQueue`)中排队等待处理。 3. **消息循环**:`Looper`类负责管理消息队列,它通过一个无限循环不断地从消息队列中取出消息并交给`Handler...

    Android App中实现图片异步加载的实例分享

    2、在图片加载类初始化时,我们会在一个子线程中维护一个Loop实例,当然子线程中也就有了MessageQueue,Looper会一直在那loop停着等待消息的到达,当有消息到达时,从任务队列按照队列调度的方式(FIFO,LIFO等),...

Global site tag (gtag.js) - Google Analytics