博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Looper源码分析
阅读量:3933 次
发布时间:2019-05-23

本文共 3837 字,大约阅读时间需要 12 分钟。

一、为什么Handler可以在主线程中直接可以使用呢?

因为主线程(UI线程)的Looper在应用程序开启时创建好了,即在ActivityThread.main方法中创建的,ActivityThread.main函数为Android应用程序的入口

public static void main(String[] args) {
... Process.setArgV0("
"); // 1. 创建消息循环Looper Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler(); } ... //2. 执行消息循环 Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited");}

Looper中最为重要的两个方法:

  • Looper.prepareMainLooper():该方法是Looper对象的初始化
  • Looper.loop():该方法会循环取出Message Queue的Message将取出的Message交付给相应的Handler(Looper的作用就体现在这里)

二、Looper.prepareMainLooper()

//在主线程中初始化Looperpublic static void prepareMainLooper() {
//在这里会调用prepare(boolean quitAllowed)方法 prepare(false); synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); }}//看下prepare(boolean quitAllowed)方法private static void prepare(boolean quitAllowed) {
//判断sThreadLocal是否为null,否则抛出异常 //即Looper.prepare()方法不能被调用两次 //也就是说,一个线程中只能对应一个Looper实例 if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread"); } //初始化Looper对象设置到ThreadLocal中 sThreadLocal.set(new Looper(quitAllowed));}//看下Looper的构造方法private Looper(boolean quitAllowed) {
//创建了一个MessageQueue(消息队列) //这说明,当创建一个Looper实例时,会自动创建一个与之配对的MessageQueue(消息队列) mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread();}

整个Looper的初始化准备工作就完了,这里做了哪几件事:

  • Looper的创建会关联一个MessageQueen的创建
  • Looper对象只能被创建一次
  • Looper对象创建后被存放在sThreadLocal

三、Looper.loop()

public static void loop() {
//myLooper()方法作用是返回sThreadLocal存储的Looper实例,如果me为null,loop()则抛出异常 //也就是说loop方法的执行必须在prepare方法之后运行 //也就是说,消息循环必须要先在线程当中创建Looper实例 final Looper me = myLooper(); if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } //获取looper实例中的mQueue(消息队列) final MessageQueue queue = me.mQueue; Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); //进入消息循环 for (;;) {
//next()方法用于取出消息队列里的消息 //如果取出的消息为空,则线程阻塞 Message msg = queue.next(); if (msg == null) {
return; } final Printer logging = me.mLogging; if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try {
//消息派发:把消息派发给msg的target属性,然后用dispatchMessage方法去处理 //Msg的target其实就是handler对象,下面会继续分析 msg.target.dispatchMessage(msg); } finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag); } } if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } 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(); }}

整个Looper的循环过程就完了,这里做了哪几件事:

  • 取出Looper和MessageQueen
  • 进入消息循环,有消息则分发出去
  • 消息资源的回收

四、Looper的退出

Looper也提供了两个方法可以退出一个Looper:

  • quit():quit会直接退出Looper
  • quitSafety():quitSafety只是设定一个退出标记,然后把消息队列中的已有消息处理完毕后退出Looper

转载地址:http://mjqgn.baihongyu.com/

你可能感兴趣的文章
read selection
查看>>
optimization on macOS
查看>>
Template-Based 3D Model Fitting Using Dual-Domain Relaxation
查看>>
install libfreenect2 on ubuntu 16.04
查看>>
how to use automake to build files
查看>>
using matlab drawing line graph for latex
查看>>
How package finding works
查看>>
build opencv3.3.0 with VTK8.0, CUDA9.0 on ubuntu9.0
查看>>
how to compile kinfu_remake with cuda 9.0 opencv2.4.13.4
查看>>
qtcreator4.4.1中cmake 与cmake3.5.1本身generate出来的setting是有区别的解决方法
查看>>
CMake Useful Variables/Logging Useful Variables
查看>>
使用cmake建立工程链接OPENNI2
查看>>
ubuntu下解决csdn网页打不开的问题
查看>>
uninstall software on ubuntu
查看>>
install kinnect senor on ubuntu
查看>>
calibrate kinnect v1 on ubuntu
查看>>
flann中关于数据的stride
查看>>
cv::Mat ptr 和 at 注意事项
查看>>
cuda更新过后, findcuda找不到怎么办?
查看>>
cast shared_ptr to shared_ptr
查看>>