Handler原理分析

作为一个开发小白,我以前写代码是这样的

private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        ......
    }
};

但是有个问题
This Handler class should be static or leaks might occur (anonymous android.os.Handler)

这个Handler class应该是static,否则可能会内存泄漏。学习了新的写法。

private static class MyHandler extends Handler {
    //保持对Activity的引用
    private final WeakReference mActivityWeakReference;
    
    //通过构造方法传入Activity
    public MyHandler(MainActivity activity) {
        mActivityWeakReference = new WeakReference<>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        BaseActivity activity = mActivityWeakReference.get();
        if (activity == null) {
            super.handleMessage(msg);
            return;
        }
        switch (msg.what) {
            case DOWNLOAD_FAILED:
                ....
                break;
            case DOWNLOAD_SUCCESS:
                .....
                break;
            default:
                super.handleMessage(msg);
                break;
        }
    }
}

使用的时候直接调用

private final MyHandler mHandler = new MyHandler(this);

//使用Handler进行延时操作,实际上发送的也是Message
mHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
        imageView.setVisibility(View.VISIBLE);
    }
},1000);
            
//使用子线程下载图片
new Thread(new Runnable() {
    @Override
    public void run() {
        Bitmap bitmap = downloadImage();

        Message msg = Message.obtain();
        msg.obj = bitmap;
        msg.what = bitmap==null?DOWNLOAD_FAILED:DOWNLOAD_SUCCESS;

        handler.sendMessage(msg);
    }
}).start();   

所以我决定看一下学习一下Handler的机制。

为什么postDelayed()发送的也是Message?

public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

public final boolean postDelayed(Runnable r, long delayMillis)
{
    //方法1
    return sendMessageDelayed(getPostMessage(r), delayMillis);
}

/**
 * 方法1
 */
private static Message getPostMessage(Runnable r) {
    //获取消息,到这里我们就明白了为什么是Message了
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

/**
 * 除了sendMessageAtFrontOfQueue()方法之外,其它的发送消息方法最终都会走到这里
 */ 
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    //消息阻塞队列
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    //sendMessageAtFrontOfQueue返回的是enqueueMessage(queue, msg, 0);
    return enqueueMessage(queue, msg, uptimeMillis);
}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    //先看一下Message再看怎么消息排列
    return queue.enqueueMessage(msg, uptimeMillis);
}

Message

作用:包含任意数据对象的消息,用于发送给Handler

获取Message实例的方式

//获取Message实例的方式
Message msg1 = new Message();
Message msg1 = Message.obtain();
Message msg2 = Handler.obtainMessage();

public final class Message implements Parcelable {
    
    /**
     * 用户自定义消息码
     */
    public int what;
    
    /**
     * arg1和arg2是Message自带的用来传递一些轻量级存储int类型的数据,比如进度条的数据等。
     * 通过这个数据是通过Bundle的方式来转载的
     */ 
    public int arg1;
    
    public int arg2;
    
    /**
     * 用来传递一些对象
     */
    public Object obj;
    
    /**
     * 线程通信时候使用
     */ 
    public Messenger replyTo;
    
    ....
}

/**
 * 平时获取消息会调用此方法,sPool为当前消息对象池,sPool实际就是单项链表
 * 当sPool = null的时候才会new Message(),如果不是,就从sPool里面拿实例
 */
public static Message obtain() {
    //锁对象,在定义时候初始化,随后只读不写
    synchronized (sPoolSync) {
        if (sPool != null) {
            //典型的链表结构
            //比如 原本消息是  1(sPool) - 2(m.next) - 3 取走了1
            //现在就剩下 2(sPool) - 3了  
            Message m = sPool;  //
            sPool = m.next;  //相当于把2置顶
            m.next = null;  // 相当于把原来的1的下一个节点引用置为null,因为此时m.next(1)还在指向2
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    //如果对象池中没有就返回一个新的Message
    return new Message();
}

MessageQueue

/**
 * 用于将消息排队,提供消息入队的方法
 * when 就是SystemClock.uptimeMillis() + delayMillis,就是你创建消息的时间+你要延迟的时间
 */ 
boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }

    synchronized (this) {
        //判断是否退出
        msg.markInUse();
        msg.when = when;
        //以前的消息链表的头部
        Message p = mMessages;
        boolean needWake;
        //什么时候为when == 0 呢? 就是使用sendMessageAtFrontOfQueue
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            //置为头部,最前面,因为需要最先发送
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            // Inserted within the middle of the queue.  Usually we don't have to wake
            // up the event queue unless there is a barrier at the head of the queue
            // and the message is the earliest asynchronous message in the queue.
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            //一直循环判断时间,确定合适的位置
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            //需要唤醒发送就调用底层线程间通信发送(现在还没了解=-=)
            nativeWake(mPtr);
        }
    }
    return true;
}

void recycleUnchecked() {
    // Mark the message as in use while it remains in the recycled object pool.
    // Clear out all other details.
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = -1;
    when = 0;
    target = null;
    callback = null;
    data = null;

    synchronized (sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            //把前一个Message存起来置为当前Message的next
            next = sPool;
            //把当前的Message放在最前面
            sPool = this;
            sPoolSize++;
        }
    }
}

ActivityThread:

public static void main(String[] args) {   
    ....
    //初始化主线程Looper
    Looper.prepareMainLooper();
    ....
    //系统启动的时候就会执行looper的loop方法
    Looper.loop();
}

Looper:

static final ThreadLocal sThreadLocal = new ThreadLocal();

public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

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

public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;
    ....
    //一直循环
    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
        ....
        try {
            //分发消息,调用Handler的dispatchMessage方法内部调用的是我们常常重写的handleMessage方法
            msg.target.dispatchMessage(msg);
            ....
        } finally {
            ...
        }
        ....
        //回收一些资源
        msg.recycleUnchecked();
    }
}

ThreadLocal

ThreadLocal并不是本地线程,而是线程本地变量
就是使Looper在不同的线程下获取的值不同,主线程是主线程的,Thread1是Thread1的
使用场景:当某些数据时以线程为作用域而且不同的线程获得的数据不同

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

void createMap(Thread t, T firstValue) {
    //可见Thread中有个ThreadLocalMap
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

/**
 * 专门存放要进行本地化的线程数据的Map
 */
ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {
    table = new Entry[INITIAL_CAPACITY];
    //这里放的位置和HashMap的计算方式一样,可以去看HashMap的原理
    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
    table[i] = new Entry(firstKey, firstValue);
    size = 1;
    //设置阈(yu)值
    setThreshold(INITIAL_CAPACITY);
}

/**
 * 存值操作,有了Map就直接存值
 */
private void set(ThreadLocal key, Object value) {

    // We don't use a fast path as with get() because it is at
    // least as common to use set() to create new entries as
    // it is to replace existing ones, in which case, a fast
    // path would fail more often than not.

    Entry[] tab = table;
    int len = tab.length;
    //这里还是和HashMap一样,,,可见HashMap中用了多么巧妙的算法
    int i = key.threadLocalHashCode & (len-1);

    for (Entry e = tab[i];
         e != null;//循环的时候判断是否e为空
         e = tab[i = nextIndex(i, len)] // 如果e != null 那么就存到i + 1的位置,如果超过了大小就放在0
         ) {
        ThreadLocal k = e.get();

        //从弱引用中获取值
        if (k == key) {
            e.value = value;
            return;
        }

        if (k == null) {
            //替换Entry
            replaceStaleEntry(key, value, i);
            return;
        }
    }

    //tab[i] 为空,也就是表中没有这个数据
    tab[i] = new Entry(key, value);
    int sz = ++size;
    //更新了数据而且数据量过大了就重新hash
    if (!cleanSomeSlots(i, sz) && sz >= threshold)
        rehash();
}

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

总结一下

用下郭霖大神的图。

Handler原理分析_第1张图片
Handler流程图.png

明白了原来有些事情需要我们去钻研。去深入,给自己加油 打call~!

你可能感兴趣的:(Handler原理分析)