介绍

Handler是Android应用内通讯组件,可实现线程间的通讯如子线程获取网络数据须在主线程更新UI使用,Handler通讯由

现在虽然不流行这样的方式但是我们还是需要了解其内部的原理

组件介绍

  • Handler(消息发送接收)
  • Message(消息体)
  • MessageQueue(消息队列)
  • Looper(轮询器)

Handler

  private Handler handler = new Handler(Looper.getMainLooper()) {        @Override        public void handleMessage(@NonNull Message msg) {            switch (msg.what) {                //what可以理解为消息类型                case 1:                    Object obj = msg.obj;                    Log.e("MainActivity", "handleMessage: " + obj);                    break;                default:                    Log.e("MainActivity", "handleMessage: default message");                    break;            }        }    };

这里声明了一个持有主线程Looper的Handler对象我们可以在handlerMessage函数中对接收到消息进行相应的处理

Message message = handler.obtainMessage();        message.what = 1;        message.obj = "this is Handler Message body";        handler.sendMessage(message);

这里我们发送了一条消息,将会被handlerMessage中接收并且处理,值得注意的是获得Message对象我们应该使用obtainMessage()函数获取这样可以节省内存,为什么可以节省内存了我们继续往下看

我们来看一下obtainMessage的源码就知道啦

  @NonNull    public final Message obtainMessage()    {        return Message.obtain(this);    }   public static Message obtain(Handler h) {        Message m = obtain();        m.target = h;        return m;    }    public static Message obtain() {        synchronized (sPoolSync) {        //sPool 不等于null的话就会复用sPool            if (sPool != null) {                Message m = sPool;                sPool = m.next;                m.next = null;                m.flags = 0; // clear in-use flag                sPoolSize--;                return m;            }        }        //直接新建了一个Message对象        return new Message();    }

在上述代码片段中我们可以看到obtainMessage最终执行了obtain函数,如果sPool不等于null的情况下就会复用sPool这个Message对象,所以这就是为什么推荐使用obtainMessage获取Message对象的原因了

Message

Message就是消息内容啦,可以理解为生活中你在某宝买了东西卖家给你寄过来的包裹

MessageQueue

MessageQueue就是消息池啦,我们调用sendMessage(),sendEmptyMessageDelayed(),sendEmptyMessageAtTime()这些函数其实就是把Message对象存放到Handler对应的MessageQueue中

   public boolean sendMessageAtTime(@NonNull 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;        }        return enqueueMessage(queue, msg, uptimeMillis);    }

这里其实就是把消息放进了消息池,那么就有小伙伴在线这个MessageQueue是哪来的呢?
那我们看下Looper这个东东就知道啦

Looper

Looper是个什么东东呢? 首先我们看下官方的解释

Class used to run a message loop for a thread. Threads by default do
not have a message loop associated with them; to create one, call
{@link #prepare} in the thread that is to run the loop, and then
{@link #loop} to have it process messages until the loop is stopped.

大概的意思是这是一个运行线程消息循环的类,默认和创建这个线程进行关联

final MessageQueue mQueue;

看下源码发现mQueue是它的一个成员变量并且用final修饰了,那么我们直接去构造函数找mQueue的初始化了

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

这里可以看到是直接new了一个MessageQueue对象仔细一看构造居然是private修饰的那这个对象是在哪里创建的呢

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

这里就是创建Looper对象的地方啦,那为什么我们之前使用handler发送消息的时候没有调用prepare()函数也没报异常呢,这是因为我们刚才创建的Handler使用的是MainThread的Looper所以我们不需要自己调用一遍prepare()了.

哈哈哈,讲了半天没讲到重点消息发送我知道到MessageQueue那消息是怎么让handlerMessage()处理的呢?

  public static void loop() {     ...      for (;;) {            Message msg = queue.next(); // might block            if (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);            }            // Make sure the observer won't change while processing a transaction.            final Observer observer = sObserver;            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;            Object token = null;            if (observer != null) {                token = observer.messageDispatchStarting();            }            long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);            try {                msg.target.dispatchMessage(msg);                if (observer != null) {                    observer.messageDispatched(token, msg);                }                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;            } catch (Exception exception) {                if (observer != null) {                    observer.dispatchingThrewException(token, msg, exception);                }                throw exception;            } finally {                ThreadLocalWorkSource.restore(origWorkSource);                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();        }    }

这里有个for死循环一直从消息池中取消息

Message msg = queue.next(); // might block            if (msg == null) {                // No message indicates that the message queue is quitting.                return;            }

在往下看我们有这么一行代码msg.target.dispatchMessage(msg)
其实这个target就是发送消息的handler,所以我们再看下handler的dispatchMessage()函数拿到这个msg都干了些啥

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

这里最终就把消息调到了handleMessage()就是我们处理消息这里

我们上面说到MainThread不需要我们去调用Looper.loop()来启动这个轮询,但是子线程中的Handler我们就需要调用下面两个函数来使这个Handler正常运作起来

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

看到这个函数的最后一行这里创建了一个对应线程的Looper对象,需要注意的是这个函数只能调用一遍否则将会抛出异常 “Only one Looper may be created per thread”

接下来就是调用Looper.loop()了,至此子线程中的Handler也能正常使用了.

更多相关文章

  1. Binder 学习笔记
  2. setVolumeControlStream(int streamType)
  3. Android的MediaPlayer架构介绍 补充
  4. Android中bindService()启动Service的过程分析
  5. 一只不务正业的程序猿玩出个Processing交互库
  6. LogUtils:一个强大的Android日志管理器,支持对象、List、Map、数组
  7. Android进程-zygote进程
  8. AsyncTask的坑,Handler,Looper与MessageQueue
  9. 最详细的Android(安卓)Bitmap回收机制(从2.3到7.0,8.0)

随机推荐

  1. android lifecycle库监听app生命周期 app
  2. listView背景问题以及限制editText字数以
  3. Android获得所有存储设备位置最佳方式
  4. BAT等公司Android面试题集锦
  5. Android 文档查看: word、excel、ppt、pdf
  6. 【Android】防止UI界面被输入法遮挡(画面
  7. Android之Activity生命周期浅析
  8. Android 自定义View(Canvas和Path)绘制基
  9. Android 发送系统广播ACTION_MEDIA_SCANN
  10. android 测试项目出现 Test run failed: