Android开发经验谈Android开发技术干货

Handler使用原理

2020-03-06  本文已影响0人  涛涛123759

Android中UI的更新在主线程中完成,为了避免ANR异常所以耗时的操作需要在子线程中完成。由于主线程和子线程中需要消息的传递就引入了Hander消息传递机制。

一、首先看一下handler的使用过程

public class MainActivity extends AppCompatActivity {
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
               ***
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mHandler.sendEmptyMessage("0");
            }
        }).start();
    }
}

二、handler运行机制

借用别人的一张图来讲解一下:::



 Handler机制也可叫异步消息机制,它主要由4个部分组成:Message,Handler,MessageQueue,Looper,其中增加了ThreadLocal来管理Looper.

1.Message
  Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。使用Message的arg1和arg2便可携带int数据,使用obj便可携带Object类型数据。target用来保存当前的handler。

2.Handler
  Handler顾名思义就是处理者的意思,它只要用于在子线程发送消息对象Message,在UI线程处理消息对象Message,在子线程调用sendMessage方法发送消息对象Message,而发送的消息经过一系列地辗转之后最终会被传递到Handler的handleMessage方法中,最终在handleMessage方法中消息对象Message被处理。

3.MessageQueue
  MessageQueue就是消息队列的意思,它只要用于存放所有通过Handler发送过来的消息。这部分消息会一直存放于消息队列当中,等待被处理。每个线程中只会有一个MessageQueue对象,请牢记这句话。其实从字面上就可以看出,MessageQueue底层数据结构是队列,而且这个队列只存放Message对象。

4.Looper
  Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当MesssageQueue中存在一条消息,Looper就会将这条消息取出,并将它传递到Handler的handleMessage()方法中。每个线程只有一个Looper对象。

5.ThreadLocal
通过引用ThreadLocalMap的map对象来管理不同线程中的Looper。通过get()/set()方法来获取和存储Looper.

三、handler源码分析

1、发送消息

使用Handler发送消息主要有两种,一种是sendXXXMessage方式,还有一个postXXX方式,不过两种方式最后都会调用到sendMessageDelayed方法,所以我们就以最简单的sendMessage()方法来分析。

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

   public final boolean sendMessage(Message msg) {
        return sendMessageDelayed(msg, 0);
    }

调用sendMessageDelayed()方法,默认delayMillis为0

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

在调用sendMessageAtTime时,传入的时间值: 系统时钟+delayMillis

    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;
        }
        // 调用enqueueMessage,把消息加入到MessageQueue中
        return enqueueMessage(queue, msg, uptimeMillis);
    }
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        //msg.target标记为当前Handler对象
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

在MessageQueue中把接受到的Message存到MessageQueue中。然后根据延迟的时间片when把不同得消息存放到Message单链表中,按延迟的时间从小到大从链表头部依次排列。

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

2、读取消息

Looper.loop()的作用就是:从当前线程的MessageQueue从不断取出Message,并调用其相关的方法。代码如下:

 public static void loop() {
        //1、获取Looper对象
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        //2、获取消息队列
        final MessageQueue queue = me.mQueue;
        Binder.clearCallingIdentity();
        ***
        for (;;) {
            //3、通过死循环读取MessageQueue中的Message
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            ***
            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            try {
              //4、通过Message中的target找到当前Message中的Handler分发消息
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
           
            ***
            //5、回收资源
            msg.recycleUnchecked();
        }
    }

首先还是判断了当前线程是否有Looper,然后得到当前线程的MessageQueue。接下来,就是最关键的代码了,写了一个死循环,不断调用MessageQueue的next方法取出MessageQueue中的Message,注意,当MessageQueue中没有消息时,next方法会阻塞,导致当前线程挂起。

拿到Message以后,会调用它的target的dispatchMessage方法,这个target其实就是发送消息时用到的Handler。所以就是调用Handler的dispatchMessage方法,代码如下:

 public void dispatchMessage(Message msg) {
        // 如果msg.callback不是null,则调用handleCallback
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            // 如果 mCallback不为空,则调用mCallback.handleMessage方法
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            // 调用Handler自身的handleMessage,这就是我们常常重写的那个方法
            handleMessage(msg);
        }
    }
    public void handleMessage(Message msg) {
    }
3、ActivityThread

主线程中在ActivityThread的main方法中创建Looper对象,所以在主线程中创建Hander时不用创建Looper对象。在子线程中需要手动创建Looper对象。

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        CloseGuard.setEnabled(false);
        Environment.initForCurrentUser();
        EventLogger.setReporter(new EventLoggingReporter());
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);
        Process.setArgV0("<pre-initialized>");
        //1、创建Looper,并将Looper保存到ThreadLocal中
        Looper.prepareMainLooper();
        long startSeq = 0;
        if (args != null) {
            for (int i = args.length - 1; i >= 0; --i) {
                if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                    startSeq = Long.parseLong(
                            args[i].substring(PROC_START_SEQ_IDENT.length()));
                }
            }
        }
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
          //2、开启死循环读取消息
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
4、Looper机制

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

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

从上面的代码可以看出,一个线程最多只有一个Looper对象。当没有Looper对象时,去创建一个Looper,并存放到sThreadLocal中。

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

这里主要就是创建了消息队列MessageQueue,并让它供Looper持有,因为一个线程最大只有一个Looper对象,所以一个线程最多也只有一个消息队列。然后再把当前线程赋值给mThread。
MessageQueue的构造方法没有什么可讲的,它就是一个消息队列,用于存放Message。
所以Looper.prepare()的作用主要有以下三点
1、创建Looper对象
2、创建MessageQueue对象,并让Looper对象持有
3、让Looper对象持有当前线程

5、ThreadLocal

通过引用ThreadLocalMap的map对象来管理不同线程中的Looper。通过get()/set()方法来获取和存储Looper.

    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();
    }
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
6、Message

保存当前线程中发送消息的信息

    /*package*/ int flags;
    /*package*/ long when;
    /*package*/ Bundle data;
  //包当前的Handler保存在target中,用区分Message在那个Hander中的
    /*package*/ Handler target;
    /*package*/ Runnable callback;
    // sometimes we store linked lists of these things
    /*package*/ Message next;

    *****
   public static Message obtain(Handler h) {
        Message m = obtain();
        //记录Hander对象
        m.target = h;

        return m;
    }

上一篇下一篇

猜你喜欢

热点阅读