Android核心原理源码解析

Handler

放入消息主要函数

Android核心原理源码解析_第1张图片

Handler工作流程

1. 子线程调用Handler的boolean sendMessage()方法,最终调用MessageQueue中的boolean enqueueMessage(Message msg, long when) 方法,将msg放入到MessageQueue消息队列中

2. Loop调用public static void loop() 方法,loop()方法会执行一个死循环,不断的调用Message msg = queue.next();方法获取消息,获取到消息后,通过msg.target.dispatchMessage(msg);方法派遣消息,然后dispatchMessage这个方法最终会调用Handler的handlerMessage方法执行我们自己写的逻辑

public final class Looper {
    public static void loop() {
        final Looper me = myLooper();
        ...
        final MessageQueue queue = me.mQueue;
        ...
        for (;;) {
            //相当于获取消息
            Message msg = queue.next(); // might block
            ...
            try {
                //获取消息后,派遣消息
                msg.target.dispatchMessage(msg);
                ...
            }
            ...
        }
    }
}

public class Handler {
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //触发handleMessage处理消息,需要自己实现的方法
            handleMessage(msg);
        }
    }
}

一个线程只有一个Loop,原理?

应用开始启动的时候,首先会调用ActivityThread的main方法,main方法会执行一个Looper.prepareMainLooper();初始化Looper

Looper能启动的原因,是因为loop是因为main方法中调用的loop方法,这个方法是一个死循环,这个死循环会不断的轮询msg

1. 如何初始化Looper的?

main方法中调用Looper.prepareMainLooper();

public final class Looper {
    private static Looper sMainLooper; //主Looper
    static final ThreadLocal sThreadLocal = new ThreadLocal();

    @Deprecated
    public static void prepareMainLooper() {
        prepare(false);//向ThreadLocal中初始化一个Looper
        synchronized (Looper.class) {
            if (sMainLooper != null) {//保证了一个线程只能创建一个Looper
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();//sMainLooper的值从ThreadLocal中获取
        }
    }
    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();
    }

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

2.Handler内存泄漏

1. 原因

Handler在调用sendMessage的时候,这个方法会调用到Handler的enqueueMessage方法,这个方法会将Handler赋值给msg的target

MessageQueue持有msg,这时msg对象会持有Handler的引用,Handler中有 this Activity,那么this Activity中大量内存都不会释放,就会造成大量的内存泄漏

如果是一个延迟消息,那么这个消息会一直在MessageQueue中,msg-Handler-this Activity ,那么内存就一直没办法回收

public class 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声明为静态类,②用软引用或弱引用来持有activity

③在destroy方法里面清理handler中的所有Message

3. 为什么主线程可以new handler?如何在子线程中new handler

①为什么主线程中可以new Handler

在应用启动的时候,Looper就被初始化好了,在ActivityThread调用Looper.prepareMainLooper();//初始化Looper,在调用Handler的构造器时,会将Looper传给Handler的Looper,构造器没有添加Looper,默认添加主线程的Looper

new Looper源码

public class Handler {
    private static final boolean FIND_POTENTIAL_LEAKS = false;
    private static final String TAG = "Handler";
    private static Handler MAIN_THREAD_HANDLER = null;
    ...
    @UnsupportedAppUsage
    final Looper mLooper;
    final MessageQueue mQueue;
    @UnsupportedAppUsage
    final Callback mCallback;
    final boolean mAsynchronous;
    @UnsupportedAppUsage
    IMessenger mMessenger;
    ...

    @Deprecated
    public Handler() {
        this(null, false);
    }
    public Handler(@Nullable Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class 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

用法

        HandlerThread handlerThread = new HandlerThread("name");
        handlerThread.start();
        Handler handler = new Handler(handlerThread.getLooper()) {
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
                //...自己实现的方法
            }
        };

上述代码对应源码解析

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    public int getThreadId() {
        return mTid;
    }
}

public class Handler {
    ...
    public Handler(@NonNull Looper looper) {
        this(looper, null, false);
    }
    @UnsupportedAppUsage
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    ...
}

4. 子线程中维护的Looper,消息队列中无消息的时候应该怎么处理?有什么作用?主线程呢?

①当消息队列中没有消息的时候,怎么处理

当消息队列中没有消息的时候,在调用next()函数的时候会休眠,应该调用Looper类的quitSafely()函数,让loop()函数退出;

②作用

当loop()函数退出,这时线程就会退出,线程所占用的资源就都会被释放

如果需要重新发送消息,这时重新创建一个子线程对应的Handler就好,重新创建Looper

Looper类对应源代码如下

public final class Looper {
    ...
    public static void loop() {
        final Looper me = myLooper();
        ...
        for (;;) {
            //相当于获取消息
            Message msg = queue.next();
            if (msg == null) {
                return;//退出loop()函数
            }
            ...
        }
    }
}

public final class MessageQueue {
    ...
    @UnsupportedAppUsage
    Message next() {
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
            nativePollOnce(ptr, nextPollTimeoutMillis);//睡眠
            synchronized (this) {
            ...
                if (msg != null) {
                    ...
                } else {
                    nextPollTimeoutMillis = -1;
                }
                if (mQuitting) {
                    dispose();
                    return null;//这里会退出死循环,返回null
                }
                ...
            }
            ...
        }
        ...
    }
    ...
}

Looper类的quitSafety()方法对应源码

public final class Looper {
    ...
    public void quitSafely() {
        mQueue.quit(true);
    }
    ...
}

public final class MessageQueue {
    ...
    void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }

            //唤醒因为没有消息而睡眠的线程
            nativeWake(mPtr);
        }
    }
    ...
    private void removeAllMessagesLocked() {
        Message p = mMessages;
        while (p != null) {
            Message n = p.next;
            p.recycleUnchecked();
            p = n;
        }
        mMessages = null;
    }
    //移除掉所有的Message
    private void removeAllFutureMessagesLocked() {
        final long now = SystemClock.uptimeMillis();
        Message p = mMessages;
        if (p != null) {
            if (p.when > now) {
                removeAllMessagesLocked();
            } else {
                Message n;
                for (;;) {
                    n = p.next;
                    if (n == null) {
                        return;
                    }
                    if (n.when > now) {
                        break;
                    }
                    p = n;
                }
                p.next = null;
                do {
                    p = n;
                    n = p.next;
                    p.recycleUnchecked();
                } while (n != null);
            }
        }
    }
}

③主线程没有消息怎样处理

会一直休眠,必须不可以退出

5. 既然可以存在多个Handler往MessageQueue中添加数据(发消息时各个Handler可能处于不同线程),如何保证线程安全?取消息呢

①多个Handler发消息,如何保证线程安全?

Looper中的MessageQueue是唯一的,多个Handler中的MessageQueue是来自于Looper中的MessageQueue,线程和Looper一一对应,Looper和MessageQueue一一对应,每一个线程只有一个MessageQueue

而且向MessageQueue中添加消息需要加锁,以此来保证线程安全

对应源码

public final class Looper {
    ...
    @UnsupportedAppUsage
    final MessageQueue mQueue;
    ...
    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();
    }
}

public class Handler {
    ...
    @UnsupportedAppUsage
    final Looper mLooper;
    final MessageQueue mQueue;
    @UnsupportedAppUsage
    final Callback mCallback;
    final boolean mAsynchronous;
    @UnsupportedAppUsage
    IMessenger mMessenger;
    ...
    @UnsupportedAppUsage
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
}

public final class MessageQueue {
    @UnsupportedAppUsage
    Message mMessages;
    ...
    boolean enqueueMessage(Message msg, long when) {
        ...
        synchronized (this) {
            ...
        }
        ...
    }
}

②取消息,如何保证线程安全

取消息的时候,锁的是MessageQueue,以此来保证取消息线程安全

public final class MessageQueue {
    @UnsupportedAppUsage
    Message next() {
        ...
        for (;;) {
            ...
            synchronized (this) {
                ...
            }
        }
    }
}

6. 我们使用Message的时候,应该如何创建它?

使用 Message message = Message.obtain(); 创建,这里运用了享元设计模式

public final class Message implements Parcelable {
    private static Message sPool;
    ...
    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();
    }
    ...
    @UnsupportedAppUsage
    void recycleUnchecked() {
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = UID_NONE;
        workSourceUid = UID_NONE;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
}

public final class Looper {
    public static void loop() {
        ...
        for (;;) {
            ...
            msg.recycleUnchecked();
            ...
        }
    }
}

7.handler的消息阻塞是怎么实现的,为什么主线程不会阻塞

Looper对象调用loop方法的next()方法会阻塞

当一个消息进入队列中的时候,会唤醒阻塞的loop()方法

public final class MessageQueue {
    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        synchronized (this) {
            if (msg.isInUse()) {
                throw new IllegalStateException(msg + " This message is already in use.");
            }
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            //将msg插入到消息队列的头部,并将mMessages指向当前msg
            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 {               
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                //队列以时间顺序,从头到尾依次较小,将当前msg插入到合适的位置mMessages
                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;
            }
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }
}  

 

你可能感兴趣的:(Android)