现在的位置: 首页 > 移动开发 > 正文

【Android个人理解(一)】通过Looper与Handle的关系,理解Looper工作机制

2019年06月02日 移动开发 ⁄ 共 3722字 ⁄ 字号 评论关闭

Looper与Handle是Android独有的新概念,但我们学习中常常将他们分开学习,实际上两者密不可分。
Looper与Handle的关系:
Looper是负责在线程里建立消息循环的类,包括准备,开始循环,停止等整个消息循环的生命周期。Handle是负责不同线程之间消息的类,包括消息的发送,接受,清除等消息的生命周期。
但是只有存在Looper的线程,才会用到Handle。没有Handle,Looper无法接收消息,也就无法实现功能。
我们通过Looper与Handle的源码来分析:
Looper.java

    private static final ThreadLocal sThreadLocal = new ThreadLocal();  
    public static final void prepare() {  
            if (sThreadLocal.get() != null) {  
                throw new RuntimeException("Only one Looper may be created per thread");  
            }  
            sThreadLocal.set(new Looper());  
    }  

这里说明通过prepare()创建Looper对象。同时Android也规定一个线程只能有一个Looper。
由上new Looper(),我们看 Looper的构造方法。

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

可以看到在Looper的构造函数中,创建了一个消息队列对象mQueue,此时,调用Looper. prepare()的线程就建立起一个消息循环的对象。

再开始看Handle的源码:
Handle.java

    final MessageQueue mQueue;  
     final Looper mLooper;  
    public Handler() {  
            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 = null;  
    }  

倒数第五行”Can’t create handler inside thread that has not called Looper.prepare()” 说明Handle的使用必须存在 Looper.prepare(),即必须存在信息队列,这样Handle才能找到信息。Handler通过mLooper = Looper.myLooper()绑定到线程的局部变量Looper上去,同时Handler通过mQueue =mLooper.mQueue获得线程的消息队列。

而没有Handle处理信息即handleMessage (Message msg){},只有Looper的信息队列在循环,信息就没有价值,用武之地。

而我们平时用Handle时,只是在UI线程中却没有声明Looper,是因为UI线程本身默认含有Looper机制。这个我们程序报错时经常看到“looper”。

最后总结工作原理:
1、 初始化Looper,启动消息循环。

2、 绑定handler到CustomThread实例的Looper对象

3、 在Looper循环中,通过Handle发送或一直等待消息。

4、 Handle通过Looper得到消息,处理消息。

附代码实例和更多Looper实现机制源码:

    package com.zhuozhuo;  

    import android.app.Activity;  
    import android.os.Bundle;  
    import android.os.Handler;  
    import android.os.Looper;  
    import android.os.Message;  
    import android.util.Log;  
    import android.view.View;  
    import android.view.View.OnClickListener;  

    public class LooperThreadActivity extends Activity{  
        /** Called when the activity is first created. */  

        private final int MSG_HELLO = 0;  
        private Handler mHandler;  

        @Override  
        public void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.main);  
            new CustomThread().start();//新建并启动CustomThread实例  

            findViewById(R.id.send_btn).setOnClickListener(new OnClickListener() {  

                @Override  
                public void onClick(View v) {//点击界面时发送消息  
                    String str = "hello";  
                    Log.d("Test", "MainThread is ready to send msg:" + str);  
                    mHandler.obtainMessage(MSG_HELLO, str).sendToTarget();//发送消息到CustomThread实例  

                }  
            });  

        }  





        class CustomThread extends Thread {  
            @Override  
            public void run() {  
                //建立消息循环的步骤  
                Looper.prepare();//1、初始化Looper  
                mHandler = new Handler(){//2、绑定handler到CustomThread实例的Looper对象  
                    public void handleMessage (Message msg) {//3、定义处理消息的方法  
                        switch(msg.what) {  
                        case MSG_HELLO:  
                            Log.d("Test", "CustomThread receive msg:" + (String) msg.obj);  
                        }  
                    }  
                };  
                Looper.loop();//4、启动消息循环  
            }  
        }  
    }  

Google源码:

private class Worker implements Runnable {
        private final Object mLock = new Object();
        private Looper mLooper;

        /**
         * Creates a worker thread with the given name. The thread
         * then runs a {@link android.os.Looper}.
         * @param name A name for the new thread

         */
        Worker(String name) {
            Thread t = new Thread(null, this, name);
            t.setPriority(Thread.MIN_PRIORITY);
            t.start();
            synchronized (mLock) {
                while (mLooper == null) {
                    try {
                        mLock.wait();
                    } catch (InterruptedException ex) {
                    }
                }
            }
        }

        public Looper getLooper() {
            return mLooper;
        }

        public void run() {
            synchronized (mLock) {
                Looper.prepare();
                mLooper = Looper.myLooper();
                mLock.notifyAll();
            }
            Looper.loop();
        }

        public void quit() {
            mLooper.quit();
        }
    }

抱歉!评论已关闭.