Anddroid开发之Handler机制原理分析

2019-08-03  本文已影响0人  zhangwenhao

Anddroid开发之Handler机制原理分析

标签(空格分隔): Android知识总结


整个流程

一张图片搞懂Hand0ler

Message

synchronized (sPoolSync) {
    if (sPoolSize < MAX_POOL_SIZE) {
        next = sPool;
        sPool = this;
        sPoolSize++;
    }
}
Message message1 = new Message();   //直接 new 出一个 Message
Message message2 = Message.obtain();    //通过 obtain()方法返回一个 Message

obtain() 方法,顾名思义,获取,那么他从哪里获取的呢?那就是从一个 消息池 中得到的,这个消息池是共享的,各个线程都可以访问。可以看到下面的 obtain() 方法的源码,加了一个同步锁保证了线程安全,如果消息池中还有一个 Message 的头节点不为空,则直接将其返回,如果消息池中没有消息了,那么就创建一个新的消息,然后将其返回。

public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}

MessageQueue

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

ThreadLocal

//set() 方法就是将 value 值存入 当前线程中的 ThreadLocalMap 中的静态内部类 Entry 中去
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

//下面是 ThreadLocalMap 的 getMap() 方法
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}
//get() 方法就是从 ThreadLocalMap 中的 静态内部类 Entry 中拿出来
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();
}

Looper

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

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}
//myLoper() 方法
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

//looper() 方法
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 {
            msg.target.dispatchMessage(msg);
            if (observer != null) {
                observer.messageDispatched(token, msg);
            }
            
             ···
            
            msg.recycleUnchecked();
        }
    }
}

Handler

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
        long uptimeMillis) {
       
   ···
       
    return queue.enqueueMessage(msg, uptimeMillis);
}
//简单构造方法
public Handler() {
    this(null, false);
}

//最终调用的构造方法,当然不只这一个
public Handler(@Nullable Callback callback, boolean async) {
        
        ···
        
    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;
}
//handleCallback() 方法
private static void handleCallback(Message message) {
    message.callback.run();
}

//dispatchMessage() 方法
public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

Handler是怎么做到线程切换的

注意Handler的内存泄露问题

解决方法

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyHandler myHandler = new MyHandler(this);
        myHandler.post(MyHandler.runnable);
    }

    //解决Handler的内存泄漏问题
    static class MyHandler extends Handler {
        
        private final WeakReference<MainActivity> mActivity;

        MyHandler(MainActivity activity) {
            mActivity = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            //拿到强引用进行判空操作
            MainActivity activity = mActivity.get();
            //进行判空操作
            if (activity != null) {
                //对消息执行一些操作
            }
        }
        //也可以不写这一步
        private static Runnable runnable = new Runnable() {
            @Override
            public void run() {
                //写一些任务
            }
        };
    }
}
上一篇下一篇

猜你喜欢

热点阅读