Handler 讲解

1.Looper

1.1 Looper源码及使用

源码:

一般线程使用例子:   
  * class LooperThread extends Thread {
    *      public Handler mHandler;
    *      public void run() {
    *          Looper.prepare(); //一般线程创建looper
                         //ActivityThread创建 Looper.prepareMainLooper()
   
  *          mHandler = new Handler() { //里面会获取当前线程的looper
    *              public void handleMessage(Message msg) {
    *                 .......
    *              }
    *          };
    
*          Looper.loop(); //looper 循环
    *      }
    *}


public final class Looper {
    private static final String TAG = "Looper";
    // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();//线程隔离
    private static Looper sMainLooper;  // guarded by Looper.class
    final MessageQueue mQueue;
    final Thread mThread;

    private Printer mLogging;
    private long mTraceTag;
    private long mSlowDispatchThresholdMs;
    private long mSlowDeliveryThresholdMs;
    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() { //ActivityThread主线程创建方式
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    public static Looper getMainLooper() { //获取ActivityThread主线程looer
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

    public static void loop() { //looper循环
        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;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;

        for (;;) {
            Message msg = queue.next(); // 阻塞
            if (msg == null) { //退出循环唯一条件msg =null
                // No message indicates that the message queue is quitting.
                return;
            }
            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;

            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            try {
                msg.target.dispatchMessage(msg); //回调handler中的dispatchMessage方法 --> handleMessage
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
            }

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycleUnchecked(); //资源回收
        }
    }

    private static boolean showSlowLog(long threshold, long measureStart, long measureEnd,
            String what, Message msg) {
        final long actualTime = measureEnd - measureStart;
        if (actualTime < threshold) {
            return false;
        }
        // For slow delivery, the current message isn't really important, but log it anyway.
        Slog.w(TAG, "Slow " + what + " took " + actualTime + "ms "
                + Thread.currentThread().getName() + " h="
                + msg.target.getClass().getName() + " c=" + msg.callback + " m=" + msg.what);
        return true;
    }

    public static @Nullable Looper myLooper() { //获取当前线程的looper
        return sThreadLocal.get();
    }

    public static @NonNull MessageQueue myQueue() { //获取当前线程的Queue
        return myLooper().mQueue;
    }

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

    public boolean isCurrentThread() { //判断当前线程和looper是否相等
        return Thread.currentThread() == mThread;
    }

    public void setMessageLogging(@Nullable Printer printer) {
        mLogging = printer;
    }

    /** {@hide} */
    public void setTraceTag(long traceTag) {
        mTraceTag = traceTag;
    }

    public void setSlowLogThresholdMs(long slowDispatchThresholdMs, long slowDeliveryThresholdMs) {
        mSlowDispatchThresholdMs = slowDispatchThresholdMs;
        mSlowDeliveryThresholdMs = slowDeliveryThresholdMs;
    }


    public void quit() {
        mQueue.quit(false);
    }

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

    public @NonNull Thread getThread() { //返回当前线程
        return mThread;
    }

    public @NonNull MessageQueue getQueue() {
        return mQueue;
    }

    public void dump(@NonNull Printer pw, @NonNull String prefix) {
        pw.println(prefix + toString());
        mQueue.dump(pw, prefix + "  ", null);
    }

    public void dump(@NonNull Printer pw, @NonNull String prefix, Handler handler) {
        pw.println(prefix + toString());
        mQueue.dump(pw, prefix + "  ", handler);
    }

    /** @hide */
    public void writeToProto(ProtoOutputStream proto, long fieldId) {
        final long looperToken = proto.start(fieldId);
        proto.write(LooperProto.THREAD_NAME, mThread.getName());
        proto.write(LooperProto.THREAD_ID, mThread.getId());
        mQueue.writeToProto(proto, LooperProto.QUEUE);
        proto.end(looperToken);
    }

    @Override
    public String toString() {
        return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
                + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}";
    }
}

1.2 looper分步骤讲解

1.2.1 looper创建

ActivityThread主线程调用方式:Looper.prepareMainLooper();
//prepare(false); 表示消息队列不可以销毁
其他线程创建方式:Looper.prepare(); //prepare(true); 表示消息队列可以销毁
源码:

public static void prepareMainLooper() { //ActivityThread主线程调用方式
        prepare(false); //false 消息队列不可以quit
        synchronized (Looper.class) {
          if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
          }
          sMainLooper = myLooper();
       }
}

public static void prepare() { //其他线程创建方式
       prepare(true); //true 消息队列可以退出
}

private static void prepare(boolean quitAllowed) {
       if (sThreadLocal.get() != null) { //不为空表示当前线程已经创建了looper
           throw new RuntimeException("Only one Looper may be created per thread");
       }
      sThreadLocal.set(new Looper(quitAllowed)); //一个线程只能创建一个looper
}

prepare有两个重载的方法,主要看 prepare(boolean quitAllowed) quitAllowed的作用是在创建MessageQueue时
标识消息队列是否可以销毁, ActivityThread主线程不可被销毁

1.2.2 创建MessageQueue以及Looper与当前线程的绑定

源码:

looper:
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);//创建MessageQueue AcrivityThread(false),其他线程为true
        mThread = Thread.currentThread(); //绑定当前线程
    }

MessageQueue:
    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed; //quitAllowed false true决定队列是否可以销毁
        mPtr = nativeInit();
    }

1.2.3 Looper循环

1.调用方式:Looper.loop()
2.详解:
1.loop()为一个死循环,唯一跳出循环的方式是MessageQueu的next方法返回一个null
2.当Looper的quit方法被调用时,Looper就会调用MessageQueu的quit/quitSafely方法来通知消息队列退出,当消息队列被标记为退出状态时,它的next方法会返回null,也就是说,Looper必须退出,否则Looper就一直循环下去。
3.loop()调用MessageQueu的next获取消息,而next方法是一个阻塞操作,当没有消息时,next会一直阻塞在那,也导致loop方法一直阻塞在那
如果loop MessageQueu调用next 返回新的消息,Looper就会处理这条消息,msg.target.dispatchMessage(msg)
源码:

 public static void loop() { //looper循环
        final Looper me = myLooper(); //里面调用了sThreadLocal.get()获得刚才创建的Looper对象
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        } //如果Looper为空则会抛出异常
        final MessageQueue queue = me.mQueue;
   。。。。。
        for (;;) {  //这是一个死循环,从消息队列不断的取消息
            Message msg = queue.next(); // might block
            if (msg == null) {
                //由于刚创建MessageQueue就开始轮询,队列里是没有消息的,
//等到Handler sendMessage enqueueMessage后队列中才有消息
                return;
            }
。。。。。
            try {
                msg.target.dispatchMessage(msg); msg.target就是绑定的Handler,
            。。。。。。
            msg.recycleUnchecked();
        }
    }

1.2.4 looper 退出

两种方式
源码:

(1)quit() 直接退出
public void quit() {
    mQueue.quit(false);
}

(2)quitSafely() 把消息队列中已有的消息处理完成后退出
public void quitSafely() {
    mQueue.quit(true);
}

1.2.5 Looper常用方法使用

Looper.prepareMainLooper(); 主线程创建Looper(调用 prepare(false) false指主线程消息队列不可以销毁)
Looper.prepare(); 创建当前线程的looper对象(调用prepare(true) 一个线程只能有一个looper)
Looper.getMainLooper(); 获取主线程的Looper对象
Looper.loop(); loop跑起来
Looper.myLooper(); 获取当前线程的Looper对象
Looper.myQueue(); 获取当前线程的Messagequeue对象

通过looper判断,是否在主线程
1.Looper.myLooper() == Looper.getMainLooper()
2.Thread.currentThread() == Looper.getMainLooper().getThread()

looper退出条件:
循环里面的message为null

2. HandlerThread分析

2.1 HandlerThread源码

HandlerThread的本质:继承Thread类 封装Handler Looper
源码:

package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;

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

2.2 HandlerThread使用

HandlerThread的使用步骤分为5步:

// 步骤1:创建HandlerThread实例对象
// 传入参数 = 线程名字,作用 = 标记该线程
HandlerThread mHandlerThread = new HandlerThread("handlerThread");

// 步骤2:启动线程
mHandlerThread.start();
// 步骤3:创建工作线程Handler & 复写handleMessage()
// 作用:关联HandlerThread的Looper对象、实现消息处理操作 & 与其他线程进行通信
// 注:消息处理操作(HandlerMessage())的执行线程 = mHandlerThread所创建的工作线程中执行
Handler  workHandler =  new Handler(handlerThread.getLooper(), new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        switch () {
            ..//消息处理
        }
        return true;
    }
});

// 步骤4:使用工作线程Handler向工作线程的消息队列发送消息
// 在工作线程中,当消息循环时取出对应消息 & 在工作线程执行相关操作
  // a. 定义要发送的消息
  Message msg = Message.obtain();
  msg.what = 2; //消息的标识
  msg.obj = "B"; // 消息的存放
  // b. 通过Handler发送消息到其绑定的消息队列
  workHandler.sendMessage(msg);

// 步骤5:结束线程,即停止线程的消息循环
  mHandlerThread.quit();

3.MessageQueue分析(单链表结构 时间优先级队列)

消息队列,按照时间的先后顺序排列,在初始化Looper对象时会创建一个与之关联的MessageQueue,创建handler是会获取MessageQueue
时间采用:SystemClock.uptimeMillis() 表示系统开机到目前的毫秒数
不用System.currentTimeMillis() 方法产生一个标准的自1970年1月1号0时0分0秒所差的毫秒数,因为System.currentTimeMillis()可以手动更改

(1)Handler 一般使用方式:
Handler handler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what){
            case 0:
                break;
        }
        return false;
    }
});
Message message = Message.obtain();
message.what = 0;
handler.sendMessage(message);


handler发生消息,不管调用那个方法,最终会调用到 enqueueMessage 在调用到 MessageQueue中的 enqueueMessage
handler.sendMessage() --> sendMessageDelayed(msg, 0) -> sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis) -> enqueueMessage

Handler:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this; //将Message 与handler绑定
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis); //调用MessageQueue 中的enqueueMessage
}

MessageQueue工作流程模型:
在这里插入图片描述

3.1 MessageQueue中两个重要方法:

(1)enqueueMessage(Message msg, long when)
目的:插入消息到消息队列
唤醒Looper中等待的线程(如果是及时消息并且线程是阻塞状态)
(2)next() 从队列头部取出消息

3.1.1 enqueueMessage 模型/源码:

在这里插入图片描述
源码:

Message mMessages; //链表的头部
boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) { //先判断msg.target Handler是否为null
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) { //判断消息是否在使用
        throw new IllegalStateException(msg + " This message is already in use.");
    }
    synchronized (this) { //同步机制 和next() 相对应
        if (mQuitting) { //looper有没有调用quit 退出线程
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle(); //msg回收
            return false;
        }
        msg.markInUse();
        msg.when = when; //将延时时间封装到Message 里面
        Message p = mMessages; //消息队列第一个元素
        boolean needWake;
        if (p == null || when == 0 || when < p.when) { //空队列/立刻执行/执行时间比头节点小
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;//mMessages 永远指向msg 的头部
        } else { //队列不为空/延时队列 将msg 插入到比它时间小的节点前面
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) { //p指向的下一个为null/按照时间的先后顺序
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p;  //将按照时间的先后顺序将 msg 插入到节点,时间小的在前面
            prev.next = msg;
        }
        if (needWake) { //唤醒线程
            nativeWake(mPtr);
        }
    }
    return true;
}

3.1.2 next() 从队列中取出消息

每次都取头部的message
在这里插入图片描述
源码:

源码解析:
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);
//阻塞 nextPollTimeoutMillis
-1 一直阻塞不会超时
0 不会阻塞,立刻返回
>0 最长阻塞,如果有唤醒,立刻返回
        synchronized (this) { //同步机制和enqueueMessage相对应
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {//同步屏障 先判断有没有异步消息,有的话先执行异步消息
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else { //正常取出消息
                    mBlocked = false; //false 表示目前没有阻塞
                    if (prevMsg != null) { //prevMsg != null说明有异步消息
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null; //将头部msg指向下一个为null
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg; //把头部的msg 返回
                }
            } else {
                nextPollTimeoutMillis = -1;//没有消息,一直阻塞
            }
            if (mQuitting) {
                dispose();
                return null;
            }
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                mBlocked = true;
                continue;
            }
            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; 
            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }
            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }
        pendingIdleHandlerCount = 0;
        nextPollTimeoutMillis = 0;
    }
}

4.Message分析(享元设计模式)

Message 创建/回收模型:
在这里插入图片描述 源码:
创建时,obtain() 从链表的头部sPool 取出一个元素,来用,回收时,再将之前取出的元素放入链表的头部spool,spool永远指向链表的头部

 Handler target; //handler
    Runnable callback; //回调
    Message next; //指向下一个对象
    public static final Object sPoolSync = new Object(); //属于类
    private static Message sPool; //属于类 链表的头部 创建/回收时都对头部操作
    private static int sPoolSize = 0; //属于类

    private static final int MAX_POOL_SIZE = 50; //链表最多50个

//构造
public static Message obtain() { //创建的时候将链表的头部赋值给新的对象
     synchronized (sPoolSync) {
         if (sPool != null) {
             Message m = sPool;
             sPool = m.next;
             m.next = null;
             m.flags = 0; 
             sPoolSize--;
             return m;
         }
     }
     return new Message();
}

//回收 对应looper中的 msg.recycleUnchecked();
void recycleUnchecked() { //回收时,将新的对象放入到头部
    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) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}

Handler接收与处理的消息对象
(1)初始化Message对象:
Message message= new Message();
Message message= Message.obtain();
Messager message= handler.obtaionMessager();
(2) 向Message中添加数据:
Message message = Message.obtain();
//TODO 将传递数据,封装到Message消息对象中
message.what = 0;
message.arg1 = 1;
message.arg2 = 2;
message.obj = “传递的内容”;
Bundle bundle = new Bundle();
bundle.putString(“name”,“张三”);
message.setData(bundle);
(3)获取Message中存储的数据
private Handler handler = new Handler()
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int flag1 = msg.what;
int flag2 = msg.arg1;
int flag3 = msg.arg2;
String resultMsg = (String) msg.obj;
Bundle bundle = msg.getData();
String name = bundle.getString(“name”);
}
};

5 Handler分析

5.1 工作流程模型

在这里插入图片描述
handler机制就是一个传送带的运转机制
1)MessageQueue就像履带。
2)Thread就像背后的动力,就是我们通信都是基于线程而来的。
3)传送带的滚动需要一个开关给电机通电,那么就相当于我们的loop函数,而这个loop里面的for循环就会带着不断
的滚动,去轮询messageQueue
4)Message就是 我们的货物了。

5.2 Handler的创建

源码:

(1)方式1,创建没有回调函数,回调会调用覆盖重写的handleMessage
Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
    }
};

(2)方式2:
Handler handler1 = new Handler(Looper.myLooper(), new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        return false;
    }
});
。。。。

5.3 源码

public Handler() {    
this(null, false);
}
public Handler(Callback callback, boolean async) 
{  
  。。。。。  
    mLooper = Looper.myLooper(); //获取当前线程的Looper 对象  
      if (mLooper == null) { //没有创建会抛出异常      
        throw new RuntimeException(            "Can't create handler inside thread " + Thread.currentThread()                    + " that has not called Looper.prepare()");    } 
        mQueue = mLooper.mQueue; //获取Looper 对象的mQueue          mCallback = callback; //获取回调函数   
         mAsynchronous = async;}
。。。。。
public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

5.4 Handler发送消息

Handler发送消息有很多种,常用sendMessage(Message), post(Runnable r)
(1)sendMessage(Message)-> sendMessageDelayed-> sendMessageAtTime-> enqueueMessage-> queue.enqueueMessage
(2)post(Runnable r) -> sendMessageDelayed ->sendMessageAtTime-> enqueueMessage-> queue.enqueueMessage

不管调用那个方法最终都会调用到enqueueMessage 调用MessageQueue中的enqueueMessage,将消息保存到消息队列中,唤醒队列
然后又由Looper取出,调用 Message msg = queue.next(); 调用 msg.target.dispatchMessage(msg)

5.5 Message和Handler进行绑定

创建Message的时候可以通过 Message.obtain(Handler h) 这个构造方法绑定。当然可以在 在Handler 中的enqueueMessage()也绑定了,所有发送Message的方法都会调用此方法入队,所以在创建Message的时候是可以不绑定的
源码

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this; //将Message 和Handler进行 绑定
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

5.6 Handler接受消息

源码

public void dispatchMessage(Message msg) {
    if (msg.callback != null) { //handler.post(Runnable)时候才不为空
        handleCallback(msg);
    } else { //handler.sendxxx
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) { //回调mCallback 中的handleMessage
                return;
            }
        }
        handleMessage(msg); //最终执行handleMessage
    }
}

private static void handleCallback(Message message) {
    message.callback.run();
}

6.异步消息和同步屏障

Android消息队列MessageQueue中加入的消息分成同步消息和异步消息。
在平常开发中接触到的消息基本上都是同步消息,同步消息会被放到消息队列的按照时间先后顺序/或者放置队尾,Looper在消息循环时从队列头部不断取出同步消息执行。
屏障消息就是在消息队列中插入一个屏障,在屏障之后的所有同步消息都会被挡着,不能被处理。不过异步消息却例外,屏障不会挡住异步消息,因此可以这样认为:屏障消息就是为了确保异步消息的优先级,设置了屏障后,只能处理其后的异步消息,同步消息会被挡住,除非撤销屏障。

6.1 屏障消息通过 MessageQueue的postSyncBarrier方法插入到消息队列,屏障消息和普通消息的区别是tartger是null

源码:

private int postSyncBarrier(long when) {
      synchronized (this) {
        //1、屏障消息和普通消息的区别是屏障消息没有tartget。
        final int token = mNextBarrierToken++;
        final Message msg = Message.obtain();
        msg.markInUse();
        msg.when = when;
        msg.arg1 = token;

        Message prev = null;
        Message p = mMessages;
        //2、根据时间顺序将屏障插入到消息链表中适当的位置
        if (when != 0) {
            while (p != null && p.when <= when) {
                prev = p;
                p = p.next;
            }
        }
        if (prev != null) { 
            msg.next = p;
            prev.next = msg;
        } else {
            msg.next = p;
            mMessages = msg;
        }
        //3、返回一个序号,通过这个序号可以撤销屏障
        return token;
    }
-----------------------------------------------------------------------------------------------------------------------------------------------------
Message next() {
  。。。。。
        synchronized (this) { //同步机制和enqueueMessage相对应
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) { //同步屏障 先判断有没有异步消息,有的话先执行异步消息
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());//找到消息链表中最近一一条消息
            }
            if (msg != null) {
                if (now < msg.when) {
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else { //正常取出消息
                    mBlocked = false; //false 表示目前没有阻塞
                    if (prevMsg != null) { //prevMsg != null说明有异步消息
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null; //将头部msg指向下一个为null
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg; //把头部的msg 返回
} else {
// 如果没有异步消息就一直休眠,等待被唤醒。
nextPollTimeoutMillis = -1;
}
......

    }
}

总结:
postSyncBarrier

  • 屏障消息和普通消息的区别在于屏障没有tartget,普通消息有target是因为它需要将消息分发给对应的target,而屏障不需要被分发,它就是用来挡住普通消息来保证异步消息优先处理的。
  • 屏障和普通消息一样可以根据时间来插入到消息队列中的适当位置,并且只会挡住它后面的同步消息的分发。
  • postSyncBarrier返回一个int类型的数值,通过这个数值可以撤销屏障。
  • postSyncBarrier方法是私有的,如果我们想调用它就得使用反射。
  • 插入普通消息会唤醒消息队列,但是插入屏障不会。

7.IntentService

特点:
1.继承service,是一个抽象类,封装 HandlerThread
2.用于在后台执行耗时的异步任务,当任务完成后会自动停止。
3.拥有较高的优先级,不轻易被系统杀死。
使用步骤:
1.继承IntentService
2.在Manifest.xml中注册服务
3.实现onHandleIntent
使用场景:
按顺序,在后台执行的任务。

源码:

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);//调用子类的onHandleIntent
            stopSelf(msg.arg1); //做完事后,service停止,销毁
        }
    }

    public IntentService(String name) {
        super();
        mName = name;
    }
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);//抛入消息队列
    }
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }
    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent); //子类实现,在创建时调用
}

使用例子:

步骤1:继承IntentService  重新onHandleIntent
public class myIntentService extends IntentService {
      public myIntentService() {
          // 调用父类的构造函数
          // 参数 = 工作线程的名字
          super("myIntentService");
      } 
      @Override
      protected void onHandleIntent(Intent intent) {
  
          // 根据 Intent的不同,进行不同的事务处理
          String taskName = intent.getExtras().getString("taskName");
          switch (taskName) {
              case "task1":
                  Log.i("myIntentService", "do task1");
                  break;
              case "task2":
                  Log.i("myIntentService", "do task2");
                  break;
              default:
                  break;
          }
      }
}
步骤2:在Manifest.xml中注册服务
<service android:name=".myIntentService">
            <intent-filter >
                <action android:name="cn.scu.finch"/>
            </intent-filter>
</service>
步骤3:在Activity中开启Service服务
startService 会多次调用myIntentService  onStart会将消息,传入到消息队列中。
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

            // 同一服务只会开启1个工作线程
            // 在onHandleIntent()函数里,依次处理传入的Intent请求
            // 将请求通过Bundle对象传入到Intent,再传入到服务里

            // 请求1
            Intent i = new Intent("cn.scu.finch");
            Bundle bundle = new Bundle();
            bundle.putString("taskName", "task1");
            i.putExtras(bundle);
            startService(i);
            
            // 请求2
            Intent i2 = new Intent("cn.scu.finch");
            Bundle bundle2 = new Bundle();
            bundle2.putString("taskName", "task2");
            i2.putExtras(bundle2);
            startService(i2);

            startService(i);  //多次启动
        }
    }

以上就是对handler的简单总结,博客有错误的地方麻烦读者在评论区指出,不胜感激

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值