Android的Handler深入解析

1、概述

前面写过一篇文章《Android中的消息机制》简单分析了异步消息机制,本文将深入解读Handler的原理。

2、基本概念

  • 单线程模型中的Message、Handler、Message Queue、Looper之间的关系:

Handler获取当前线程的Looper对象,Looper用来从存放Message的MessageQueue中取出Message,再由Handler进行Message的分发和处理。

(1)Message Queue(消息队列)

用来存放通过Handler发布的消息,通常附属于某一个创建它的线程,可以通过Looper.myQueue()得到当前线程的消息队列。

(2)Handler

可以发布或者处理一个消息或者操作一个Runnable,通过Handler发布消息,消息将只会发送到与它关联的消息队列,然也只能处理该消息队列中的消息。

Handler处理者,是Message的主要处理者,负责Message的发送,Message内容的执行处理。后台线程就是通过传进来的 Handler对象引用来sendMessage(Message)。而使用Handler,需要implement 该类的 handleMessage(Message)方法,它是处理这些Message的操作内容,例如Update UI。通常需要子类化Handler来实现handleMessage方法。

(3)Looper

是Handler和消息队列之间通讯桥梁,程序组件首先通过Handler把消息传递给Looper,Looper把消息放入队列。Looper也把消息队列里的消息广播给所有的。

Looper是每条线程里的Message Queue的管家。Android没有Global的Message Queue,而Android会自动替主线程(UI线程)建立Message Queue,但在子线程里并没有建立Message Queue。所以调用Looper.getMainLooper()得到的主线程的Looper不为NULL,但调用Looper.myLooper() 得到当前线程的Looper就有可能为NULL。

(4)Handler

Handler接受到消息后调用handleMessage进行处理。

(5)Message

消息的类型,在Handler类中的handleMessage方法中得到单个的消息进行处理。

(6)ThreadLocal

ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有在指定的线程中可以获取到指定的数据,对于其他线程来说则无法获取数据。一般来说,当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal。

比如,对于Handler来说,它需要获取当前线程的Looper,很显然Looper的作用域是线程并且不同线程具有不同的Looper,这个时候通过ThreadLocal就可以轻松实现Looper在线程中的存取。

3、源码分析

通过Handler处理信息流程图:

(1)Looper.prepare()

//Looper类中的方法
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函数的构造函数
private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
  • 首先创建了Looper对象,在构造函数中创建MessageQueue。
  • 然后将Looper对象通过ThreadLocal与当前主线程绑定。

(2)handler = new Handler()

//Handler.class
public Handler(Callback callback, boolean async) {
    //获取主线程中的Looper对象
    mLooper = Looper.myLooper();
    //获取MessageQueue的引用
    mQueue = mLooper.mQueue;
    }

//Looper.class
//返回ThreadLocal中的Looper对象
public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
  • 通过Looper类中的ThreadLocal从主线程中获取到Looper对象
  • 然后通过Looper对象获取了MessageQueue的引用

(3)handler.sendMessage(Message msg)

//Handler.class
public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

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

 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        //找到消息MessageQueue的对象
        MessageQueue queue = mQueue;
        return enqueueMessage(queue, msg, uptimeMillis);
    }

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        //将handler对象成为msg的一个成员对象
        msg.target = this;
        return queue.enqueueMessage(msg, uptimeMillis);
    }
  • 通过sendMessageAtTime方法中的MessageQueue queue = mQueue;找到消息MessageQueue对象
  • 通过enqueueMessage方法中的msg.target = this;,将handler对象成为msg对象大的一个成员变量
  • 最后将msg添加到MessageQueue中

(4)Looper.loop()

//Looper.class
public static void loop() {
    final Looper me = myLooper();
    //找到MessageQueue
    final MessageQueue queue = me.mQueue;
    //死循环遍历消息队列
    for (;;) {
            // Message采用阻塞队列
            Message msg = queue.next(); // might block
            //调用handler的dispatchMessage方法
            msg.target.dispatchMessage(msg);
    }
    //Handler.class
     public void dispatchMessage(Message msg) {
            handleMessage(msg);
    }        
  • 首先找到MessageQueue
  • 开启死循环遍历MessageQueue池
  • 当取到msg的时候,通过msg.target找到发送这个msg的handler
  • 然后调用handler的dispatchMessage方法,即调用用户重写handleMessage方法

(5)Handler使用案例

package com.chunsoft.testhandler;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    Handler myHandler  = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    Toast.makeText(MainActivity.this, "异步消息发送成功", Toast.LENGTH_SHORT).show();
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.btn1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(2*1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        Message msg = new Message();
                        msg.what = 1;
                        myHandler.sendMessage(msg);
                    }
                }).start();
            }
        });
    }
}

4、主线程给子线程发送消息

一般的Handler使用是让子线程给主线程(UI线程)发送异步消息,在这种情况下,系统已经为主线程创建了Looper对象并通过ThreadLocal与主线程进行绑定,且在构造函数中创建了MessageQueue消息池。

在这里我们实现让主线程给子线程发送消息,更深层次掌握Looper、MessageQueue和handler之间的关系。

在主线程中创建一个线程:

new Thread(new Runnable() {
            @Override
            public void run() {
            //1.创建Looper对象,然后Looper对象中创建MessgeQueue
            //2.并将当前的Looper对象那个跟当前的线程(子线程)绑定,ThreadLocal
                Looper.prepare();

                //创建Handler对象,然后从当前线程中获取Looper对象,然后通过Looper对象获取MessageQueue的引用
                myHandler1 = new Handler(){
                    @Override
                    public void handleMessage(Message msg) {
                        switch (msg.what) {
                            case 1:
                                Toast.makeText(MainActivity.this, "来自主线程的问候", Toast.LENGTH_SHORT).show();
                                break;
                        }
                    }
                };
                //1.从当前线程中找到之前创建的Looper对象,然后找到MeaageQueue
                //2.开启死循环,遍历消息池中的消息
                //3.当获取到msg的时候,调用msg的handler的dispatchMessage方法,让msg执行起来
                Looper.loop();
            }
        }).start();

findViewById(R.id.btn2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message msg = new Message();
                msg.what = 1;
                myHandler1.sendMessage(msg);
            }
        });

5、异步消息的内存泄漏

上述代码,看起来能够实现主线程给子线程发送异步信息,但是,由于遍历消息池中的消息是死循环,当Activity死亡时,线程依旧保持对Activity的引用,因此垃圾回收无法回收Activity,导致内存泄漏。

如何解决这个问题,防止内存泄漏,最主要是让Activity在退出的时候停止Looper循环。解决方法就是获取子线程的Looper对象,将子线程生命周期与Activity生命周期绑定。在onDestory()方法中执行,myLooper.quit()和myLooper = null;操作,这样在Activity退出后,Looper循环也停止,防止了内存泄漏,完整代码如下:

package com.chunsoft.testhandler;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    //子线程中的Looper对象
    private Looper myLooper;

    Handler myHandler  = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    Toast.makeText(MainActivity.this, "异步消息发送成功", Toast.LENGTH_SHORT).show();
            }
        }
    };

    private Handler myHandler1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();

                myHandler1 = new Handler(){
                    @Override
                    public void handleMessage(Message msg) {
                        switch (msg.what) {
                            case 1:
                                Toast.makeText(MainActivity.this, "来自主线程的问候", Toast.LENGTH_SHORT).show();
                                break;
                        }
                    }
                };
                //获取当前线程中的Looper对象
                myLooper = Looper.myLooper();
                Looper.loop();
                Log.d("tag","loop()已经执行完了");

            }
        }).start();

        findViewById(R.id.btn1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(2*1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        Message msg = new Message();
                        msg.what = 1;
                        myHandler.sendMessage(msg);
                    }
                }).start();
            }
        });

        findViewById(R.id.btn2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message msg = new Message();
                msg.what = 1;
                myHandler1.sendMessage(msg);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (myLooper != null) {
            myLooper.quit();
            myLooper = null;
        }
    }
}
时间: 2024-08-04 10:28:46

Android的Handler深入解析的相关文章

android之handler机制深入解析

一.android中需要另开线程处理耗时.网络的任务,但是有必须要在UI线程中修改组件.这样做是为了: ①只能在UI线程中修改组件,避免了多线程造成组件显示混乱 ②不使用加锁策略是为了提高性能,因为android中经常使用多线程. handler就是为了解决在多个线程之间的通信问题. 二.基本使用: 1 package com.dqxst.first.multithread; 2 3 import android.app.Activity; 4 import android.os.Bundle;

深入解析Android中Handler消息机制

Android提供了Handler 和 Looper 来满足线程间的通信.Handler先进先出原则.Looper类用来管理特定线程内对象之间的消息交换(MessageExchange).Handler消息机制可以说是Android系统中最重要部分之一,所以,本篇博客我们就来深入解析Android中Handler消息机制. Handler的简单使用 为什么系统不允许子线程更新UI 因为的UI控件不是线程安全的. 如果在多线程中并发访问可能会导致UI控件处于不可预期的状态,那为什么不对UI控件的访

Android异步载入全解析之使用多线程

异步载入之使用多线程 初次尝试 异步.异步,事实上说白了就是多任务处理.也就是多线程执行.多线程那就会有各种问题,我们一步步来看.首先.我们创建一个class--ImageLoaderWithoutCaches,从命名上.大家也看出来,这个类,我们实现的是不带缓存的图像载入,不多说,我们再创建一个方法--showImageByThread,通过多线程来载入图像: /** * Using Thread * @param imageView * @param url */ public void s

Android Json数据的解析+ListView图文混排+缓存算法Lrucache 仿知乎

前几天心血来潮,打算根据看知乎的API自己做一个小知乎,定制的过程遇到ListView的优化问题及图片未缓存重加载等等许多问题,解决了以后打算和博友分享一下. 接口数据:http://api.kanzhihu.com/getpostanswers/20150925/archive 首先,Json数据太常用,相信每一位开发者Json的解析都是必备的.我们要准备以下知识: JavaBean,枚举你需要的元素,用来存储数据. 异步加载网络内容的必备途径,多线程加载+AsyncTask两种方式. Jso

Android异步载入全解析之IntentService

Android异步载入全解析之IntentService 搞什么IntentService 前面我们说了那么多,异步处理都使用钦定的AsyncTask.再不济也使用的Thread,那么这个IntentService是个什么鬼. 相对与前面我们提到的这两种异步载入的方式来说.IntentService有一个最大的特点.就是--IntentService不受大部分UI生命周期的影响.它为后台线程提供了一个更直接的操作方式.只是,IntentService的不足主要体如今下面几点: 不能够直接和UI做

Android多线程----Handler

关于Android的多线程知识,请参考本人之前的一篇博客: 在Android当中,提供了异步消息处理机制的两种方式来解决线程之间的通信问题,一种是今天要讲的Handler的机制,还有一种就是之前讲过的 AsyncTask 机制. 一.handler的引入: 我们都知道,Android UI是线程不安全的,如果在子线程中尝试进行UI操作,程序就有可能会崩溃.相信大家在日常的工作当中都会经常遇到这个问题,解决的方案应该也是早已烂熟于心,即创建一个Message对象,然后借助Handler发送出去,之

Android 之XML数据解析(2)—— SAX解析

(以下文章基本照抄郭霖大神的<第一行代码>) 在Android之 解析XML文件(1)-- Pull解析 中我们讲了Pull方式解析XML文件.今天讲另外一种方式,SAX解析XML文件. 首先还是先看代码. 一. SAX解析参考代码 private void parseXMLWithSAX(String xmlData){ try{ SAXParserFactory factory = SAXParserFactory.newInstance(); XMLReader xmlReader =

Android 请求WebService 并且解析

直接上代码: 写一个Bean,封装数据 package com.mbl.wbsconn; import java.util.List; import java.util.Map; public class BaseBean { protected String usid; protected String pwd; protected String error; protected String msgtp; protected String logonstatus; protected Lis

Android xUtils3源码解析之注解模块

xUtils3源码解析系列 一. Android xUtils3源码解析之网络模块 二. Android xUtils3源码解析之图片模块 三. Android xUtils3源码解析之注解模块 四. Android xUtils3源码解析之数据库模块 初始化 public class BaseActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { su