Android中Handler有何作用?如何使用? 您所在的位置:网站首页 handle的机制 Android中Handler有何作用?如何使用?

Android中Handler有何作用?如何使用?

2024-04-08 11:53| 来源: 网络整理| 查看: 265

一  Handler作用和概念 包含线程队列和消息队列,实现异步的消息处理机制,跟web开发的ajax有异曲同工之妙。 运行在某个线程上,共享线程的消息队列;接收消息、调度消息,派发消息和处理消息;实现消息的异步处理;

Handler能够让你发送和处理消息,以及Runnable对象;每个Handler对象对应一个Thread和Thread的消息队列。当你创建一个Handler时,它就和Thread的消息队列绑定在一起,然后就可以传递消息和runnable对象到消息队列中,执行消息后就从消息队列中退出。

Handler的作用就是:调度消息和runnable对象去被执行;使动作在不同的线程中被执行。

当一个应用程序中进程被创建时,它的主线程专门运行消息队列(messageQueue),去管理顶层的应用程序相关的对象如:activity,broadcastReceiver,windows等,你可以创建你的Thread,和主线程进行交互——通过Handler,交互的方法就是通过post或者sendMessage。但是在你的新线程中,给定的Message或者Runnable,会在适当的时候的被调度和处理。

(即不会被立即处理——阻塞式)。

实际上就是建立消息处理模型/系统

要学习Handler,看到肯定是和消息有关,可能还是需要先熟悉一下消息系统的构成和简单原理。

下面就先学习一下消息系统的基本原理。

二 消息系统的基本原理和构成

从一般的消息系统模型的建立大致构成以下几个部分:

消息原型消息队列发送消息消息循环消息获取消息派发消息处理

大致模型图如下:

消息系统模型一般会包括以上七个部分(消息原型,消息队列,消息发送,消息循环,消息获取,消息派发,消息处理)。实际上的核心是消息队列和消息循环,其余部分都是围绕这两部分进行的。

从前面文档的分析中我们知道Handler就是用来建立消息处理的系统模型,那么和这里基本消息系统模型相比,那么Handler又是如何囊括这七个部分的呢?

在Android中对这六个部分进行了抽象成四个独立的部分(消息循环):

Handler,Message,MessageQueue,Looper;

Message就是消息原型,包含消息描述和数据,MessageQueue就是消息队列,Looper完成消息循环 ,Handler就是驾驭整个消息系统模型,统领Message,MessgeQueue和Looper;

Handler能够实现消息系统模型,那么具体是如何进行工作的呢,下面探究一下这其中工作的方法和原理。

三 Handler工作原理分析

要了解Handler工作原理,先看一下这个系统模型具体组成的层次结构框架是个什么样的。

1,Looper:

实现Thread的消息循环和消息派发,缺省情况下Thread是没有这个消息循环的,即没有Looper;

需要主动去创建,然后启动Looper的消息循环loop;与外部的交互通过Handler进行;

2,MessageQueue:

消息队列,由Looper所持有,但是消息的添加是通过Handler进行;

消息循环和消息队列都是属于Thread,而Handler本身并不具有Looper和MessageQueue;

但是消息系统的建立和交互,是Thread将Looper和MessageQueue交给某个Handler维护建立消息系统模型。所以消息系统模型的核心就是Looper。消息循环和消息队列都是由Looper建立的,而建立Handler的关键就是这个Looper。

一个Thread同时可以对应多个Handler,一个Handler同时只能属于一个Thread。Handler属于哪个Thread取决于Handler在那个Thread中建立。

在一个Thread中Looper也是唯一的,一个Thread对应一个Looper,建立Handler的Looper来自哪个Thread,Handler属于哪个Thread。

故建立Thread消息系统,就是将Thread的Looper交给Handler去打理,实现消息系统模型,完成消息的异步处理。

Handler与Thread及Looper的关系可以用下面图来表示:

Handler并不等于Thread,必须通过Thread的Looper及其MessageQueue,用来实现Thread消息系统模型,依附于Thread上。

在线程建立Handler时:

使Handler满足消息系统需要的条件,将Thread中的Looper和MessageQueue交给Handler来负责维护。

在线程中建立Handler,需要做以下工作:

获取Thread中的Looper交给Handler的成员变量引用维护;通过Looper获取MessageQueue交给Handler的成员变量引用维护。

那么消息系统模型建立完成之后,按照消息系统运行,从Handler来看就是发送消息派发消息,与此线程消息系统的交互都由Handler完成。

消息发送和派发接口:

post(runnable)消息,Runnable是消息回调,经过消息循环引发消息回调函数执行;sendMessage(Message)消息,经过消息循环派发消息处理函数中处理消息;dispatchMessage派发消息,若是post或带有回调函数则执行回调函数,否则执行消息处理函数Handler的handleMessage(通常派生类重写)。

以上就是Handler如何实现Thread消息系统模型的大致介绍。下面将具体分析是如何实现消息系统模型运行的。

四 Handler实现流程分析

我们知道Handler就是一个消息系统的外壳,属于某个Thread并包装了Thread的Looper及其MessageQueue;与外部进行交互(同一个线程内或者线程之间),接收派发和处理消息,消息系统模型的核心是Looper。

下面看看Handler是如何建立跑起来的,以msg消息为例,runnable实质是一样。

1,Handler的建立

Handler唯一属于某个Thread,在某个Thread中建立Handler时,需要获取Thread的Looper及其MessageQueue,建立Handler关键是Looper的来源。

Handler提供了好几个构造函数但其本质一致:由外部传入Looper:当前线程或其他线程

  public Handler(Looper looper) {         //初始化构建消息系统参数 mLooper = looper; mQueue = looper.mQueue; mCallback = null;   }

从当前线程获取:由创建Handler的Thread决定

  public Handler() {         //初始化构建消息系统参数 mLooper = Looper.myLooper(); mQueue = mLooper.mQueue; mCallback = null;   }   public static Looper myLooper() { return sThreadLocal.get(); }

不管哪种方式,我们知道Thread在默认情况下是没有建立消息循环Looper实例的。要实现消息循环必须确保Thread的Looper建立。如何确保呢?

Looper提供了静态函数:

public static void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); } //存储线程的局部变量 static final ThreadLocal sThreadLocal = new ThreadLocal();

看到这里刚开始让我很是奇怪和迷惑:

Looper一个独立的类,又不属于某个Thread,而这里创建Looper的函数又是静态的,属于整个Looper类;创建Looper之后交给静态成员变量sThreadLocal保存,获取sThreadLocal.get(),那么一个静态变量属于整个类,属性更改始终有效。一次创建之后

sThreadLocal.get()永远都不等于null!

而Thread和Looper是唯一对应的,那这里岂不是所有的Thread都是用同一个Looper,不可能!所以肯定这个ThreadLocal是有玄机的。网上一查:

ThreadLocal:

维护线程的变量,为每个使用该变量的线程实例提供独立的变量副本,每个线程都能够独立使用该变量,而互不影响。(详细可参考:http://blog.csdn.net/qjyong/article/details/2158097)

所以每一个线程调用Looper.prepare时,都会创建为其唯一的Looper。要建立Handler,需要先创建线程的Looper,才能建立消息系统模型。通过Looper我们建立了Thread上的消息系统模型Handler,可以来进行消息系统的一系列流程了。

2,消息发送

消息发送两种方式:post和sendMessage;

post:针对runnable对象;Runnable是一个接口,就是一个回调函数(提供了run方法)sendMessage:针对Message对象;

下面通过代码具体看一下这个过程:

public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0); } public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg, 0); }

看到post和sendMessage发送消息时,仅仅是对象不同而已,Runnable和Message;但实际上都是Message的形式来描述。

这跟我通常理解的消息机制不同:

通常post消息是将消息加入到消息队列中并不立即执行就返回,send消息是立即执行等待消息执行完才返回。而这里post或者send都是将消息放入到消息队列中,然后立即返回,等待消息循环时获取消息被执行。

这里提供了众多的消息发送方法来指定消息的执行时间和顺序,具体可以查看源代码。

消息执行顺序是根据消息队列中消息的排列顺序而定。下面看一下发送消息后将消息加入到消息队列中的代码:

由Handler调用MessageQueue的enqueueMessage方法:

  final boolean enqueueMessage(Message msg, long when) { Message p = mMessages; if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; } else { Message prev = null; while (p != null && p.when


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有