Handler机制

注:此blog仅学习记录所用,如有不对的地方请大路大牛指点改正,不喜的请轻喷!


Handler实现线程间通讯,是因为共享了looper的内存,所以handlerMessage()运行在哪个线程由looper决定。而在new handler时默认使用的是主线程的looper,因此运行在主线程。

主线程创建时,消息队列和looper对象就会被创建;主线程中有一个消息轮询器looper,不断检测消息队列中是否有新消息,如果发现有新消息,自动调用此方法是在主线程中运行的;

handler为什么必须在UI线程创建?

可以先查看下handler的源码

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


// 获取到Looper
        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;
    }


从源码Handler的构造函数中可以看到,Looper .myLooper()得到Looper,然后看下 .myLooper()方法:


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

由  sThreadLocal.get 继续探入


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

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

    /**
     * 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(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

在prepareMainLooper()方法中,调用了prepare()方法中创建了一个Looper并且和sThreadLocal关联起来sThreadLocal.set(new Looper(quitAllowed)),通过这一步骤消息就和线程关联起来,不同线程质检就不能彼此访问对方的消息队列了。消息队列通过Looper和线程关联起来,而Handler又和Looper关联起来,如果我们单独开一个子线程的时候,由于没有创建Looper,所以在创建Handler的时候会抛出异常。


如果在子线程中new Handler()时会报错,如果需要在子线程中new Handler()需要先调用 Looper.myLooper(); 方法,具体实现代码如下:

     class myThread extends Thread{

         public Handler mHandler;
         public Looper mLooper;
         @Override
         public void run() {
             super.run();
             Looper.prepare();
             mLooper = Looper.myLooper();
             mHandler = new Handler(){
                 @Override
                 public void handleMessage(Message msg) {
                     super.handleMessage(msg);
                     System.out.println("" + Thread.currentThread());
                 }
             };
             Looper.loop();
         }
     }

总结:Handler一般就是用于主线程跟子线程之间的通信。比如,子线程不能更新UI,那么通过handler的sendMessage( )发送消息给主线程,而主线程在创建时,Message Queue(消息队列)和looper(轮询器对象)就会被创建,message就会放在Message Queue里,而Looper一旦发现Message Queue中有消息,就会把消息取出,然后把消息扔给Handler对象,Handler会调用自己的handleMessage方法来处理这条消息。










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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值