Android消息机制Handler深入理解

目录
  • 概述
  • Handler的使用
  • Handler架构
  • Handler的运行流程
  • 源码分析
    • 在子线程创建Handler
    • 主线程的Looper
    • Looper
    • Handler
    • 分发消息
  • 总结

概述

Handler是Android消息机制的上层接口。通过它可以轻松地将一个任务切换到Handler所在的线程中去执行。通常情况下,Handler的使用场景就是更新UI。

Handler的使用

在子线程中,进行耗时操作,执行完操作后,发送消息,通知主线程更新UI。

public class Activity extends android.app.Activity {
	private Handler mHandler = new Handler(){
		@Override
		        public void handleMessage(Message msg) {
			super.handleMessage(msg);
			// 更新UI
		}
	}
	;
	@Override
	public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
		super.onCreate(savedInstanceState, persistentState);
		setContentView(R.layout.activity_main);
		new Thread(new Runnable() {
			@Override
			             public void run() {
				// 执行耗时任务                ...
				// 任务执行完后,通知Handler更新UI
				Message message = Message.obtain();
				message.what = 1;
				mHandler.sendMessage(message);
			}
		}
		).start();
	}
}

Handler架构

Handler消息机制主要包括:MessageQueue、Handler、Looper这三大部分,以及Message。

  • Message:需要传递的消息,可以传递数据;
  • MessageQueue:消息队列,但是它的内部实现并不是用的队列,而是通过单链表的数据结构来维护消息列表,因为单链表在插入和删除上比较有优势。主要功能是向消息池投递消息( MessageQueue.enqueueMessage)和取走消息池的消息( MessageQueue.next)。
  • Handler:消息辅助类,主要功能是向消息池发送各种消息事件( Handler.sendMessage)和处理相应消息事件( Handler.handleMessage);
  • Looper:消息控制器,不断循环执行( Looper.loop),从MessageQueue中读取消息,按分发机制将消息分发给目标处理者。

从上面的类图可以看出:

  • Looper有一个MessageQueue消息队列;
  • MessageQueue有一组待处理的Message;
  • Message中记录发送和处理消息的Handler;
  • Handler中有Looper和MessageQueue。

MessageQueue、Handler和Looper三者之间的关系: 每个线程中只能存在一个Looper,Looper是保存在ThreadLocal中的。 主线程(UI线程)已经创建了一个Looper,所以在主线程中不需要再创建Looper,但是在其他线程中需要创建Looper。 每个线程中可以有多个Handler,即一个Looper可以处理来自多个Handler的消息。 Looper中维护一个MessageQueue,来维护消息队列,消息队列中的Message可以来自不同的Handler。

Handler的运行流程

在子线程执行完耗时操作,当Handler发送消息时,将会调用 MessageQueue.enqueueMessage,向消息队列中添加消息。 当通过 Looper.loop开启循环后,会不断地从消息池中读取消息,即调用 MessageQueue.next, 然后调用目标Handler(即发送该消息的Handler)的 dispatchMessage方法传递消息, 然后返回到Handler所在线程,目标Handler收到消息,调用 handleMessage方法,接收消息,处理消息。

源码分析

在子线程创建Handler

class LooperThread extends Thread {
	public Handler mHandler;
	public void run() {
		Looper.prepare();
		mHandler = new Handler() {
			public void handleMessage(Message msg) {
				// process incoming messages here
			}
		}
		;
		Looper.loop();
	}
}

从上面可以看出,在子线程中创建Handler之前,要调用 Looper.prepare()方法,Handler创建后,还要调用 Looper.loop()方法。而前面我们在主线程创建Handler却不要这两个步骤,因为系统帮我们做了。

主线程的Looper

在ActivityThread的main方法,会调用 Looper.prepareMainLooper()来初始化Looper,并调用 Looper.loop()方法来开启循环。

public final class ActivityThread extends ClientTransactionHandler {
	// ...
	public static void main(String[] args) {
		// ...
		Looper.prepareMainLooper();
		// ...
		Looper.loop();
	}
}

Looper

从上可知,要使用Handler,必须先创建一个Looper。

初始化Looper:

public final class Looper {
	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));
	}
	public static void prepareMainLooper() {
		prepare(false);
		synchronized (Looper.class) {
			if (sMainLooper != null) {
				throw new IllegalStateException("The main Looper has already been prepared.");
			}
			sMainLooper = myLooper();
		}
	}
	private Looper(Boolean quitAllowed) {
		mQueue = new MessageQueue(quitAllowed);
		mThread = Thread.currentThread();
	}
	// ...
}

从上可以看出,不能重复创建Looper,每个线程只能创建一个。创建Looper,并保存在 ThreadLocal。其中ThreadLocal是线程本地存储区(Thread Local Storage,简称TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。

开启Looper

public final class Looper {
	// ...
	public static void loop() {
		// 获取TLS存储的Looper对象
		final Looper me = myLooper();
		if (me == null) {
			throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
		}
		final MessageQueue queue = me.mQueue;
		// 进入loop主循环方法
		for (;;) {
			Message msg = queue.next();
			// 可能会阻塞,因为next()方法可能会无线循环
			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);
			}
			// ...
			final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
			final long dispatchEnd;
			try {
				// 获取msg的目标Handler,然后分发Message
				msg.target.dispatchMessage(msg);
				dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
			}
			finally {
				if (traceTag != 0) {
					Trace.traceEnd(traceTag);
				}
			}
			// ...
			msg.recycleUnchecked();
		}
	}
}

Handler

创建Handler:

public class Handler {
	// ...
	public Handler() {
		this(null, false);
	}
	public Handler(Callback callback, Boolean async) {
		// ...
		// 必须先执行Looper.prepare(),才能获取Looper对象,否则为null
		mLooper = Looper.myLooper();
		if (mLooper == null) {
			throw new RuntimeException(
			      "Can't create handler inside thread " + Thread.currentThread()
			      + " that has not called Looper.prepare()");
		}
		mQueue = mLooper.mQueue;
		// 消息队列,来自Looper对象
		mCallback = callback;
		// 回调方法
		mAsynchronous = async;
		// 设置消息是否为异步处理方式
	}
}

发送消息:

子线程通过Handler的post()方法或send()方法发送消息,最终都是调用 sendMessageAtTime()方法。

post方法:

public final Boolean post(Runnable r){
	return sendMessageDelayed(getPostMessage(r), 0);
}
public final Boolean postAtTime(Runnable r, long uptimeMillis){
	return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
public final Boolean postAtTime(Runnable r, Object token, long uptimeMillis){
	return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
public final Boolean postDelayed(Runnable r, long delayMillis){
	return sendMessageDelayed(getPostMessage(r), delayMillis);
}
private static Message getPostMessage(Runnable r) {
	Message m = Message.obtain();
	m.callback = r;
	return m;
}
 

send方法:

public final Boolean sendMessage(Message msg){
	return sendMessageDelayed(msg, 0);
}
public final Boolean sendEmptyMessage(int what){
	return sendEmptyMessageDelayed(what, 0);
}
public final Boolean sendEmptyMessageDelayed(int what, long delayMillis) {
	Message msg = Message.obtain();
	msg.what = what;
	return sendMessageDelayed(msg, delayMillis);
}
public final Boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
	Message msg = Message.obtain();
	msg.what = what;
	return sendMessageAtTime(msg, uptimeMillis);
}
public final Boolean sendMessageDelayed(Message msg, long delayMillis){
	if (delayMillis < 0) {
		delayMillis = 0;
	}
	return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
sendMessageAtTime()
public Boolean sendMessageAtTime(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);
}
private Boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
	msg.target = this;
	if (mAsynchronous) {
		msg.setAsynchronous(true);
	}
	return queue.enqueueMessage(msg, uptimeMillis);
}

分发消息

在loop()方法中,获取到下一条消息后,执行 msg.target.dispatchMessage(msg),来分发消息到目标Handler。

public class Handler {
	// ...
	public void dispatchMessage(Message msg) {
		if (msg.callback != null) {
			// 当Message存在回调方法,调用该回调方法
			handleCallback(msg);
		} else {
			if (mCallback != null) {
				// 当Handler存在Callback成员变量时,回调其handleMessage()方法
				if (mCallback.handleMessage(msg)) {
					return;
				}
			}
			// Handler自身的回调方法
			handleMessage(msg);
		}
	}
	private static void handleCallback(Message message) {
		message.callback.run();
	}
}

总结

到此这篇关于深入理解Android消息机制Handler的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android Handler机制详解原理

    Looper是整个跨线程通信的管理者 // 内部持有的变量如下: ThreadLocal<Looper> MainLooper Observer MessageQueue Thread 1.首先先回忆一下Handler怎么用 Android线程通信分为以下两种情况 1.子线程发消息给UI线程 2.UI线程发消息给子线程 3.子线程发消息给另个子线程 1.子线程发消息给UI线程 class FragmentContentActivity : AppCompatActivity() { val F

  • Android消息机制Handler用法总结

    1.简述 Handler消息机制主要包括: MessageQueue. Handler. Looper.Message. Message:需要传递的消息,可以传递数据: MessageQueue:消息队列,但是它的内部实现并不是用的队列,而是通过单链表的数据结构来维护消息列表,因为单链表在插入和删除上比较有优势.主要功能是向消息池投递消息( MessageQueue.enqueueMessage)和取走消息池的消息( MessageQueue.next).  Handler:消息辅助类,主要功能

  • 详解Android Handler的使用

    目录 Handler 概要 构造器 sendMessageAtTime dispatchMessage ThreadLocal Looper MessageQueue IdleHandler AsyncMessage和SyncBarrier 阻塞和唤醒机制 Handler内存泄漏分析 Handler 概要 Handler用于线程间的消息传递,它可以将一个线程中的任务切换到另一个线程执行.切换的目标线程与Handler内部持有的Looper所在线程一致.若初始化Handler时未手动设置Loope

  • Android Handler使用案例详解

    什么是Handler? Handler可以发送和处理消息对象或Runnable对象,这些消息对象和Runnable对象与一个线程相关联.每个Handler的实例都关联了一个线程和线程的消息队列.当创建了一个Handler对象时,一个线程或消息队列同时也被创建,该Handler对象将发送和处理这些消息或Runnable对象. handler类有两种主要用途: 执行Runnable对象,还可以设置延迟. 两个线程之间发送消息,主要用来给主线程发送消息更新UI. 为什么要用Handler 解决多线程并

  • Android Handler消息机制分析

    目录 Handler是什么? Handler 的基本使用 用法一:通过 send 方法 用法二:通过 post 方法 Handler 类 MessageQueue 类 Looper 类 Handler 的消息接收过程 Handler是什么? Handler 是一个可以实现多线程间切换的类,通过 Handler 可以轻松地将一个任务切换到 Handler 所在的线程中去执行.我们最常用的使用的场景就是更新 UI 了,比如我们在子线程中访问网络,拿到数据后我们 UI 要做一些改变,如果此时我们直接访

  • Android消息机制Handler深入理解

    目录 概述 Handler的使用 Handler架构 Handler的运行流程 源码分析 在子线程创建Handler 主线程的Looper Looper Handler 分发消息 总结 概述 Handler是Android消息机制的上层接口.通过它可以轻松地将一个任务切换到Handler所在的线程中去执行.通常情况下,Handler的使用场景就是更新UI. Handler的使用 在子线程中,进行耗时操作,执行完操作后,发送消息,通知主线程更新UI. public class Activity e

  • Android消息机制Handler的工作过程详解

    综述 在Android系统中,出于对性能优化的考虑,对于Android的UI操作并不是线程安全的.也就是说若是有多个线程来操作UI组件,就会有可能导致线程安全问题.所以在Android中规定只能在UI线程中对UI进行操作.这个UI线程是在应用第一次启动时开启的,也称之为主线程(Main Thread),该线程专门用来操作UI组件,在这个UI线程中我们不能进行耗时操作,否则就会出现ANR(Application Not Responding)现象.如果我们在子线程中去操作UI,那么程序就回给我们抛

  • Android 消息机制以及handler的内存泄露

    Handler 每个初学Android开发的都绕不开Handler这个"坎",为什么说是个坎呢,首先这是Android架构的精髓之一,其次大部分人都是知其然却不知其所以然.今天看到Handler.post这个方法之后决定再去翻翻源代码梳理一下Handler的实现机制. 异步更新UI 先来一个必背口诀"主线程不做耗时操作,子线程不更新UI",这个规定应该是初学必知的,那要怎么来解决口诀里的问题呢,这时候Handler就出现在我们面前了(AsyncTask也行,不过本质

  • Android 消息机制问题总结

    Android的消息机制几乎是面试必问的话题,当然也并不是因为面试,而去学习,更重要的是它在Android的开发中是必不可少的,占着举足轻重的地位,所以弄懂它是很有必要的.下面就来说说最基本的东西. Looper 作用: 关联起Thread 循环取出消息 1.Looper是否可以直接实例化? Looper构造方法是私有的,其中做了两件事 创建一个MessageQueue 得到与之对应的Thread private Looper(boolean quitAllowed) { mQueue = ne

  • 深入浅析Android消息机制

    在Android中,线程内部或者线程之间进行信息交互时经常会使用消息,这些基础的东西如果我们熟悉其内部的原理,将会使我们容易.更好地架构系统,避免一些低级的错误. 每一个Android应用在启动的时候都会创建一个线程,这个线程被称为主线程或者UI线程,Android应用的所有操作默认都会运行在这个线程中. 但是当我们想要进行数据请求,图片下载,或者其他耗时操作时,是不可能在这个UI线程做的,因为Android在3.0以后的版本已经禁止了这件事情,直接抛出一个异常.所以我们需要一个子线程来处理那些

  • Android 消息机制详解及实例代码

    Android 消息机制 1.概述 Android应用启动时,会默认有一个主线程(UI线程),在这个线程中会关联一个消息队列(MessageQueue),所有的操作都会被封装成消息队列然后交给主线程处理.为了保证主线程不会退出,会将消息队列的操作放在一个死循环中,程序就相当于一直执行死循环,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数(handlerMessage),执行完成一个消息后则继续循环,若消息队列为空,线程则会阻塞等待.因此不会退出.如下图所示: Handl

  • 深入剖析Android消息机制原理

    在Android中,线程内部或者线程之间进行信息交互时经常会使用消息,这些基础的东西如果我们熟悉其内部的原理,将会使我们容易.更好地架构系统,避免一些低级的错误.在学习Android中消息机制之前,我们先了解与消息有关的几个类: 1.Message 消息对象,顾名思义就是记录消息信息的类.这个类有几个比较重要的字段: a.arg1和arg2:我们可以使用两个字段用来存放我们需要传递的整型值,在Service中,我们可以用来存放Service的ID. b.obj:该字段是Object类型,我们可以

  • 代码分析Android消息机制

    我们知道在编程时许多操作(如更新UI)需要在主线程中完成,而且,耗时操作(如网络连接)需要放在子线程中,否则会引起ANR.所以我们常使用Handler来实现线程间的消息传递,这里讨论的也就是Handler的运行机制. Handler的运行主要由两个类来支撑:Looper与MessageQueue.熟悉开发的朋友都知道在子线程中默认是无法创建Handler的,这是因为子线程中不存在消息队列.当需要创建一个与子线程绑定的Handler时,标准代码如下: class LooperThread exte

  • Android编程中的消息机制实例详解

    本文实例讲述了Android编程中的消息机制.分享给大家供大家参考,具体如下: 在分析Android消息机制之前,我们先来看一段代码: public class MainActivity extends Activity implements View.OnClickListener { private TextView stateText; private Button btn; @Override public void onCreate(Bundle savedInstanceState)

随机推荐