概述:Android中的异步处理机制由四部分组成:Handler+Looper+MessageQueue+message,用于实现线程间的通信。

用到的概念:

  1. Handler: 主要作用是发送消息和处理消息。
  2. Message:封装了线程间需要传输的信息。
  3. MessageQueue:是FIFO的消息队列,用于存放Handler发送的信息,在调用Looper.prepard()方法实例化。
  4. Looper:线程通过Looper建立自己的消息循环,Looper负责从MessageQueue中取出消息,并且分发到消息指定目标Handler对象。

异步处理的流程:

  1. 首先需要在主线程中创建一个Handler对象,并且重写handlerMessage()方法
  2. 然后当子线程需要进行UI操作时,就创建一个Message对象,并通过Handler对象将这条消息发送出去。
  3. 之后这条消息会被添加到MessageQueue的队列中等待被处理。
  4. 而Looper则会一直尝试从MessageQueue中取出待处理的消息,最后发回Handler的handlerMessage()方法中。
  5. 由于Handler是在主线程中创建的,所以此时handlerMessage()方法中的代码也在主线程中执行,于是就可以安心的进行UI操作了。     

例子:在介绍原理之前,我们先介绍Android线程通讯的一个例子,这个例子实现点击按钮之后从主线程发送消息”hello”到另外一个名为” CustomThread”的线程。

LooperThreadActivity.java

package com.zhuozhuo;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;

public class LooperThreadActivity extends Activity{
   
 
 private final int MSG_HELLO = 0;
    private Handler mHandler;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        new CustomThread().start();//新建并启动CustomThread实例
       
        findViewById(R.id.send_btn).setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {//点击界面时发送消息
    String str = “hello”;
          Log.d(“Test”, “MainThread is ready to send msg:” + str);
    mHandler.obtainMessage(MSG_HELLO, str).sendToTarget();//发送消息到CustomThread实例
    
   }
  });
       
    }
   
   
   
   
   
    class CustomThread extends Thread {
     @Override
     public void run() {
      //建立消息循环的步骤
      Looper.prepare();//1、初始化Looper
      mHandler = new Handler(){//2、绑定handler到CustomThread实例的Looper对象
       public void handleMessage (Message msg) {//3、定义处理消息的方法
        switch(msg.what) {
        case MSG_HELLO:
         Log.d(“Test”, “CustomThread receive msg:” + (String) msg.obj);
        }
       }
      };
      Looper.loop();//4、启动消息循环
     }
    }
}

main.xml

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android
    android:orientation=”vertical”
    android:layout_width=”fill_parent”
    android:layout_height=”fill_parent”
    >
<TextView 
    android:layout_width=”fill_parent”
    android:layout_height=”wrap_content”
    android:text=”@string/hello”
    />
<Button android:text=”发送消息” android:id=”@+id/send_btn” android:layout_width=”wrap_content” android:layout_height=”wrap_content”></Button>
</LinearLayout>

原理:

我们看到,为一个线程建立消息循环有四个步骤:

  1、 初始化Looper

  2、 绑定handler到CustomThread实例的Looper对象

  3、 定义处理消息的方法

  4、 启动消息循环

下面我们以这个例子为线索,深入Android源代码,说明Android Framework是如何建立消息循环,并对消息进行分发的。

1、 初始化Looper : Looper.prepare()

Looper.java

private static final ThreadLocal sThreadLocal = new ThreadLocal();
public static final void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException(“Only one Looper may be created per thread”);
        }
        sThreadLocal.set(new Looper());
}

一个线程在调用Looper的静态方法prepare()时,这个线程会新建一个Looper对象,并放入到线程的局部变量中,而这个变量是不和其他线程共享的(关于ThreadLocal的介绍)。下面我们看看Looper()这个构造函数:

Looper.java

final MessageQueue mQueue;
private Looper() {
        mQueue = new MessageQueue();
        mRun = true;
        mThread = Thread.currentThread();
    }

可以看到在Looper的构造函数中,创建了一个消息队列对象mQueue,此时,调用Looper. prepare()的线程就建立起一个消息循环的对象(此时还没开始进行消息循环)。

2、 绑定handler到CustomThread实例的Looper对象 : mHandler= new Handler()

Handler.java

final MessageQueue mQueue;
 final Looper mLooper;
public Handler() {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> 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 that has not called Looper.prepare()”);
        }
        mQueue = mLooper.mQueue;
        mCallback = null;
}

Handler通过mLooper = Looper.myLooper();绑定到线程的局部变量Looper上去,同时Handler通过mQueue =mLooper.mQueue;获得线程的消息队列。此时,Handler就绑定到创建此Handler对象的线程的消息队列上了。

3、定义处理消息的方法:Override public void handleMessage (Message msg){}

子类需要覆盖这个方法,实现接受到消息后的处理方法。

4、启动消息循环 : Looper.loop()

所有准备工作都准备好了,是时候启动消息循环了!Looper的静态方法loop()实现了消息循环。

Looper.java

public static final void loop() {
        Looper me = myLooper();
        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();
       
        while (true) {
            Message msg = queue.next(); // might block
            //if (!me.mRun) {
            //    break;
            //}
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }
                if (me.mLogging!= null) me.mLogging.println(
                        “>>>>> Dispatching to ” + msg.target + ” ”
                        + msg.callback + “: ” + msg.what
                        );
                msg.target.dispatchMessage(msg);
                if (me.mLogging!= null) me.mLogging.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(“Looper”, “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.recycle();
            }
        }
    }

while(true)体现了消息循环中的“循环“,Looper会在循环体中调用queue.next()获取消息队列中需要处理的下一条消息。当msg != null且msg.target != null时,调用msg.target.dispatchMessage(msg);分发消息,当分发完成后,调用msg.recycle();回收消息。

msg.target是一个handler对象,表示需要处理这个消息的handler对象。Handler的void dispatchMessage(Message msg)方法如下:

Handler.java

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

可见,当msg.callback== null 并且mCallback == null时,这个例子是由handleMessage(msg);处理消息,上面我们说到子类覆盖这个方法可以实现消息的具体处理过程。

总结:从上面的分析过程可知,消息循环的核心是Looper,Looper持有消息队列MessageQueue对象,一个线程可以把Looper设为该线程的局部变量,这就相当于这个线程建立了一个对应的消息队列。Handler的作用就是封装发送消息和处理消息的过程,让其他线程只需要操作Handler就可以发消息给创建Handler的线程。

可参考文章:Android异步消息处理机制完全解析,带你从源码的角度彻底理解

Handler+Looper+MessageQueue深入详解的更多相关文章

  1. Android异步处理三:Handler+Looper+MessageQueue深入详解

    在<Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面>中,我们讲到使用Thread+Handler的方式来实现界面的更新,其实是在非UI线程发送消息到U ...

  2. 讲讲Handler+Looper+MessageQueue 关系

    Handler+Looper+MessageQueue这三者的关系其实就是Android的消息机制.这块内容相比开发人员都不陌生,在面试中,或者日常开发中都会碰到,今天就来讲这三者的关系. 概述: H ...

  3. Handler Looper MessageQueue 之间的关系

    Handler Looper MessageQueue 之间的关系 handler在安卓开发中常用于更新界面ui,以及其他在主线程中的操作.内部结构大概图为: 1.handler持有一个Looper对 ...

  4. android Handler机制之ThreadLocal详解

    概述 我们在谈Handler机制的时候,其实也就是谈Handler.Message.Looper.MessageQueue之间的关系,对于其工作原理我们不做详解(Handler机制详解). Messa ...

  5. Handler,Looper,MessageQueue流程梳理

    目的:handle的出现主要是为了解决线程间通讯. 举个例子,android是不允许在主线程中访问网络,因为这样会阻塞主线程,影响性能,所以访问网络都是放在子线程中执行,对于网络返回的结果则需要显示在 ...

  6. android学习11——Handler,Looper,MessageQueue工作原理

    Message是Handler接收和处理的消息对象. 每个线程只能拥有一个Looper.它的loop方法读取MessageQueue中的消息,读到消息之后就把消息交给发送该消息的Handler进行处理 ...

  7. 【Android面试查漏补缺】之Handler详解,带你全面理解Handler消息机制

    在安卓面试中,关于 Handler 的问题是必备的,但是这些关于 Handler 的知识点你都知道吗? 一.题目层次 Handler 的基本原理 子线程中怎么使用 Handler MessageQue ...

  8. ProGuard代码混淆技术详解

    前言     受<APP研发录>启发,里面讲到一名Android程序员,在工作一段时间后,会感觉到迷茫,想进阶的话接下去是看Android系统源码呢,还是每天继续做应用,毕竟每天都是画UI ...

  9. Handler Looper 解析

    文章讲述Looper/MessageQueue/Handler/HandlerThread相关的技能和使用方法. 什么是Looper?Looper有什么作用? Looper是用于给线程(Thread) ...

随机推荐

  1. 百万年薪python之路 -- 内置函数

    内置对象(68个)第一部分 内置函数一共68个 一些可以重要性不高的内置函数,只需了解即可 all() any() bytes() callable() chr() ord() complex() d ...

  2. (五)Unity插件生成

    1)新建空的AndroidStudio工程,但是新建过程时最小SDK版本要与unity一致,如下图所示,本次操作均为api16 2)创建Library,如下图所示,新建module,然后选择Andro ...

  3. Spring IoC的概念

    Spring IoC的基础知识 Spring 框架可以说是Java世界中最成功的框架,它的成功来自于理念,而不是技术,它最核心的理念是IoC(控制反转)和AOP(面向切面编程),其中IoC是Sprin ...

  4. Blazor之ABC

    .net core正式推出了Blazor, 正好在一个小项目里试用一下. 建立项目 因为基于WebAssemble的客户端Blazor还不是正式版, 为了避免不必要的麻烦,我试用服务端的Blazor. ...

  5. 全方面讲解TensorFlow

    任何曾经试图在 Python 中只利用 NumPy 编写神经网络代码的人都知道那是多么麻烦.编写一个简单的一层前馈网络的代码尚且需要 40 多行代码,当增加层数时,编写代码将会更加困难,执行时间也会更 ...

  6. 用Unity做游戏,你需要深入了解一下IL2CPP

    这次我们翻译了一篇Unity官方博客上的文章,原文题目为AN INTRODUCTION TO IL2CPP INTERNALS ,作者是从事Unity软件开发的Joshua Peterson.文章的看 ...

  7. Spring入门介绍

    概述 下载地址:https://repo.spring.io/release/org/springframework/spring/ spring是开源的轻量级框架 spring核心的主要两部分 AO ...

  8. 泛微ecology OA系统某接口存在数据库配置信息泄露漏洞

    2漏洞详情 攻击者可通过该漏洞页面直接获取到数据库配置信息,攻击者可通过访问存在漏洞的页面并解密从而获取数据库配置信息,如攻击者可直接访问数据库,则可直接获取用户数据,由于泛微e-cology默认数据 ...

  9. linux sudo root 权限绕过漏洞(CVE-2019-14287)

    0x01 逛圈子社区论坛 看到了 linux sudo root 权限绕过漏洞(CVE-2019-14287) 跟着复现下 综合来说 这个漏洞作用不大  需要以下几个前提条件 1.知道当前普通用户的密 ...

  10. Web for pentester_writeup之XSS篇

    Web for pentester_writeup之XSS篇 XSS(跨站脚本攻击) Example 1 反射性跨站脚本,URL中name字段直接在网页中显示,修改name字段, Payload: h ...