• Android源码学习(1) Handler


    Handler的实例化

    在安卓开发中,经常会用到Handler将任务提交到指定线程(例如主线程)去执行或者让其延迟执行。Handler的构造函数有多种重载形式,但最终都调用到如下两种之一:

    public Handler(Callback callback, boolean async) {
        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;
    }
    
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

    可以看到:这两个构造函数的区别只是Looper的获取方式不一样,当未指定Looper时,Handler内部会通过Looper.myLooper()静态方法,获取当前线程的Looper。我们往Handler上发送的Message或者Runnable正是由这个Looper(或该Looper的线程)负责处理的。我们可以通过Looper.getMainLooper()获取主线程的Looper。

    发送Message或者Runnable

    调用post、postAtTime、postDelayed提交Runnable,调用sendMessage、sendEmptyMessage、sendMessageDelayed、sendEmptyMessageDelayed、sendMessageAtTime、sendEmptyMessageAtTime发送Message,最终都调用到sendMessageAtTime:

     1 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
     2     MessageQueue queue = mQueue;
     3     if (queue == null) {
     4         RuntimeException e = new RuntimeException(
     5                 this + " sendMessageAtTime() called with no mQueue");
     6         Log.w("Looper", e.getMessage(), e);
     7         return false;
     8     }
     9     return enqueueMessage(queue, msg, uptimeMillis);
    10 }
    11 
    12 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    13     msg.target = this;
    14     if (mAsynchronous) {
    15         msg.setAsynchronous(true);
    16     }
    17     return queue.enqueueMessage(msg, uptimeMillis);
    18 }

    也就是说,提交的Runnable最终会被包装成Message,此时Message的callback字段将指向该Runnable。所有提交的Message都将会被插入名为mQueue的有序队列中,排序的依据便是传入的uptimeMillis(该值在enqueueMessage操作中会被赋给Message的when字段)。MessageQueue使用生产者-消费者模式,post*和send*产生的消息,最终会被Looper消费。(第2行中将mQueue赋给局部变量queue再通过改变访问mQueue,显然是出于多线程并发的安全性考虑)

    使用postAtFrontOfQueue、sendMessageAtFrontOfQueue可以分别提交Runnable和Message到mQueue的队首,该Runnable或者Message将在Looper的下次循环中处得到处理。

    使用removeCallbacks、removeMessages、removeCallbackAndMessages可以移除掉已经提交的Runnable或者Message。

    消息处理

    Handler通过dispatchMessage处理往其发送的消息:

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

    如果是Runnable,将直接执行;如果是普通的Message,将交由handlMessage进行处理。自定义Handler时,通过重写handlMessage进行具体处理。

  • 相关阅读:
    datatables出现横向滚动条
    mumu模拟器设置代理/打开网络连接(windows)
    a标签下划线
    python 配置导入方式
    redis命令
    django+mongodb 内置用户控制
    异常补充
    关于异常的总结
    java 常用类的方法
    java 日期时间类加Calendar的set和add方法
  • 原文地址:https://www.cnblogs.com/moderate-fish/p/7618330.html
Copyright © 2020-2023  润新知