Android基础之关于Handler的基础原理总结

 

Handler消息循环机制是Android为多线程更新UI的一套消息传输机制。

Handler的消息循环主要由四部分组成,

  1. Handler:处理消息的类
  2. Looper:是一个线程本地变量(ThreadLocal),其中封装了MessageQue队列。是一个接收消息并且保存到queue中,自身一直在循环取queue中数据的过程,具备线程安全机制,且内部只维护一个消息队列。
    • 还有一些运行静止状态的回调 ,有兴趣可以看下循环取消息的地方 (这里可以在ActivityThread类中看到一些应用)
    • 关于每次消息执行时间的打点的回调执行 , 有兴趣可以看下取到消息后的地方 (可以使用来检测卡顿配合帧率回调可以记录app运行性能)
  3. MessageQue是一个线程安全的队列,looper通过不断的循环来拿队列中的消息,如果队列是空的话则会阻断,直到有消息到来,拿到新的消息去处理。
  4. Message:消息内容的封装,会持有Handler的实例(target属性,此处是内存泄漏的一个地方),在消息处理的时候其实是通过target的属性来进行消息处理。

关于四者以及Thread的关系

  1. Handler创建需要一个Looper
public Handler() {
  this(null, false);
}

public Handler(@Nullable Callback callback) {
  this(callback, false);
}

public Handler(@NonNull Looper looper) {
  this(looper, null, false);
}

public Handler(@NonNull Looper looper, @Nullable Callback callback) {
  this(looper, callback, false);
}

...

 public Handler(@Nullable 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 " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

     看最后一个我们直接new Handler()的最后会执行到的构造函数

  • looper 是由Looper的类给出的静态方法,可以看到,我们是每次调用方法静态的属性会创建好,ThreadLocal线程私有存储这个可以搜资料,每个线程一个数据对象。
    
    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 @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
  • queue保存在looper中,queue会跟着looper一起是线程本地变量
  • Handler的切换线程是依赖于Looper,Looper才是每一个线程私有,这样实现了Handler方法或者消息切换线程的基础,因为Handler携带的消息会在Looper所在的线程被执行

发送的消息如何被执行

  1. looper取到消息后,?
      msg.target.dispatchMessage(msg);

    target是啥? Message内可见是Handler; 那这个Handler是什么时候赋值的呢?看到Handler就可以看见在消息放到queue时添加的

    class Message{
        
        @UnsupportedAppUsage
        /*package*/ Handler target;
    }
    
    Handler中的方法
     private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
                long uptimeMillis) {
            msg.target = this;
            msg.workSourceUid = ThreadLocalWorkSource.getUid();
    
            if (mAsynchronous) {
                msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);
        }
    

     

  2. Handler内部执行
     /**
         * Handle system messages here.
         */
        public void dispatchMessage(@NonNull Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }

     

备注1:在主线程即ActivityThread中,有着app的入口方法public static void main(String[] args),里面有着一个在线程内使用Handler消息机制的实例,在进入方法的时候会调用Looper的prepareMainLooper来创建looper,之后创建Handler实例,再次调用Looper的loop方法,这样开启了looper的无线循环。

备注2:在子线程中创建的looper需要手动停止,否则会因为阻断等待而造成线程资源不会被释放。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值