Handler、Message的简单使用

Android没有全局的消息队列,Android的消息队列是和某个线程相关联在一起的。每个线程最多只有一个消息队列,消息的处理也是在这个线程中完成。也就是说,如果想在当前线程中使用消息模型,则必须构建一个消息队列,消息机制的主要类是:Looper、Handler、MessageQueue、Message.
1、
public class

Handler

extends Object
java.lang.Object
   ↳android.os.Handler

Class Overview

A Handler allows you to send and process Message and Runnable objects associated with a thread'sMessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
 

 mHandler = new Handler(){public void handleMessage(Message msg){
//int android.os.Message.what
//User-defined message code so that the recipient can identify what this message is about.
switch(msg.what){case UPDATE_TEXT:mTextView.setText("text changed");break;default:break;}}};


public final boolean sendMessage(Message msg)Added inAPI level 1

Pushes a message onto the end of the message queue after all pending messages before the current time. It will be received inhandleMessage(Message), in the thread attached to this handler.

Returns
  • Returns true if the message was successfully placed in to the message queue. Returns false on failure, usually because the looper processing the message queue is exiting.
Message mMessage = Message.obtain(mHandler, UPDATE_TEXT);//Pushes a message onto the end of the message queue after all pending messages before the current time. 
mHandler.sendMessage(mMessage);
Handler负责将Message发送至当前线程的MessageQueue中,处理消息。发送消息一般是使用Handler的sendMessage方法,发出的消息最终会传递到Handler的handleMessage()方法中。
public final class

2、

Looper

extends Object
java.lang.Object
   ↳android.os.Looper

Class Overview

Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, callprepare() in the thread that is to run the loop, and thenloop() to have it process messages until the loop is stopped.

Most interaction with a message loop is through the Handler class. 

Looper时时刻刻监视着MessageQueue,是每个线程中的MessageQueue管家,每个线程中只有一个Looper,调用其loop()方法就会进入到一个无限循环中,每当发现MessageQueue中存在一条消息,就会把它取出,送到Handler中的handleMessage()中。
public final class
3、

MessageQueue

extends Object
java.lang.Object
   ↳android.os.MessageQueue
消息队列,每个线程中只会有一个MessageQueue。主要存放所有通过Handler发送的消息。

4、
public final class

Message

extends Object
implements Parcelable
java.lang.Object
   ↳android.os.Message

Class Overview

Defines a message containing a description and arbitrary data object that can be sent to aHandler. This object contains two extra int fields and an extra object field that allow you to not do allocations in many cases. 

//Message android.os.Message.obtain(Handler h, int what)
Message mMessage = Message.obtain(mHandler, UPDATE_TEXT);
Message是在线程之间传递消息,它可以在内部携带少量信息,如what字段、arg1、arg2来携带一些整型数据、obj携带Object对象,用于在不同线程间交换数据。

异步消息处理的整个流程:

首先需要在主线程中创建一个Handler对象,并重写handleMessage()方法;
然后,当子线程中需要UI操作时,就创建一个Message对象,并通过Handler将消息发送出去;
之后这条消息会被添加到MessageQueue队列中,等待被处理,期间Looper会一直尝试从MessageQueue中取出待处理消息,最后分发到Handler的handleMessage()方法中。由于Handler是在主线程中创建的,因此handleMessage()中的代码也会在主线程中处理。

MeloDev的Message游历:

Message

在边境X(子线程)服役的士兵Message慵懒的躺在一个人数为50(线程中最大数量)的军营(Message池)中。不料这时突然接到上司的obtain()命令,让它去首都(主线程)告诉中央领导一些神秘代码。小mMessage慌乱地整理下衣角和帽子,带上信封,准备出发。上司让士兵mMessage收拾完毕等待一个神秘人电话,并嘱咐他:到了首都之后,0是这次的暗号。
Message mMessage = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString("key","这里一切安全");
mMessage.what = 0;
mMessage.obj = bundle;
通常会用obtain()方法创建Message,如果消息池中有Message则取出,没有则创建,这样防止对象重复创建,节省资源。
obtain()方法源码:
 /*** Return a new Message instance from the global pool. Allows us to* avoid allocating new objects in many cases.*/public static Message obtain() {synchronized (sPoolSync) {if (sPool != null) {Message m = sPool;sPool = m.next;m.next = null;sPoolSize--;return m;}}return new Message();}

“铃铃铃……”,小mMessage接到一个店换,"我叫Handler,来此Activity大本营,是你这次任务的接收者,一会我会带你去首都的消息中心去报道。"

Handler:

来此Activity大本营的Handler部门是整个消息机制的核心部门,部门里有很多个Handler,这次协助小mMessage的叫mHandler.
 mHandler = new Handler(){public void handleMessage(Message msg){
//int android.os.Message.what
//User-defined message code so that the recipient can identify what this message is about.}};
Handler属于Activity,创建任何一个Handler都属于重写了Activity的Handler。

在Handler的构造中,默认完成了对当前线程Looper的绑定。
public Handler(Callback callback, boolean async) {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 = callback;mAsynchronous = async;}

通过Looper.myLooper()方法获得当前线程保存的Looper实例,通过Looper.mQueue()获得MessageQueue实例,
static LoopermyLooper()
Return the Looper object associated with the current thread.
static MessageQueuemyQueue()
Return the MessageQueue object associated with the current thread.
在此时,mHandler实例与looper、messageQueue实例关联上了。
mHandler神情骄傲的对小mMessage说:我已经跟首都的消息中心打好了招呼,准备接收你了,现在有两种车“send”和“post”你想坐哪辆都可以,不过要根据你上司的命令选择对应的型号哦~

post、send:
final booleanpost(Runnable r)
Causes the Runnable r to be added to the message queue.
final booleanpostAtFrontOfQueue(Runnable r)
Posts a message to an object that implements Runnable.
final booleanpostAtTime(Runnable r,Object token, long uptimeMillis)
Causes the Runnable r to be added to the message queue, to be run at a specific time given byuptimeMillis.
final booleanpostAtTime(Runnable r, long uptimeMillis)
Causes the Runnable r to be added to the message queue, to be run at a specific time given byuptimeMillis.
final booleanpostDelayed(Runnable r, long delayMillis)
Causes the Runnable r to be added to the message queue, to be run after the specified amount of time elapses
final booleansendEmptyMessage(int what)
Sends a Message containing only the what value.
final booleansendEmptyMessageAtTime(int what, long uptimeMillis)
Sends a Message containing only the what value, to be delivered at a specific time.
final booleansendEmptyMessageDelayed(int what, long delayMillis)
Sends a Message containing only the what value, to be delivered after the specified amount of time elapses.
final booleansendMessage(Message msg)
Pushes a message onto the end of the message queue after all pending messages before the current time.
final booleansendMessageAtFrontOfQueue(Message msg)
Enqueue a message at the front of the message queue, to be processed on the next iteration of the message loop.
booleansendMessageAtTime(Message msg, long uptimeMillis)
Enqueue a message into the message queue after all pending messages before the absolute time (in milliseconds)uptimeMillis.
final booleansendMessageDelayed(Message msg, long delayMillis)
Enqueue a message into the message queue after all pending messages before (current time + delayMillis).
StringtoString()

分析源码,post方法也是在使用send类在发送消息,除了sendMessageAtFrontOfQueue()外,其余send方法都经过层层包装走到sendMessageAtTime()中。
这时小mMessage和mHandler上了sendMessage的车,行驶在一条叫enqueueMessage的高速公路上进入MessageQueue。将Message按时间排序,放入MessageQueue中。其中mMessage.target = this,是保证每个发送Message的Handler也能处理这个Message。mHandler向小mMessage说,其实你的消息到时候也是我处理的,不过现在还不是时候,因为我很忙。

Looper

路上时间,mHandler为小mMessage热心介绍着MessageQueue和Looper。“在每个驻扎地(线程)中只有一个MessageQueue和一个Looper,他们两个是相爱相杀,同生共死的好朋友,Looper是个跑不死的邮差,一直负责取出MessageQueue中的Message”。
"不过通常只有首都(主线程)的Looper和MessageQueue是创建好的,其他地方需要我们人为创建"。
Looper提供prepare()方法来创建Looper。重复创建会抛出异常,也就是说每个线程只能有一个looper。

Looper.prepare();
static voidprepareMainLooper()
Initialize the current thread as a looper, marking it as an application's main looper.

Looper的构造方法中,创建了和他一一对应的MessageQueue
private Looper(boolean quitAllowed){mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();
}

在Android中ActivityThread的main方法是程序入口,主线程的Looper和MessageQueue就是在此刻创建。

mHandler和小mMessage来到了MessageQueue中,进入队列之前,门卫仔细给小mMessage贴上以下标签:“mHandler负责带入”、“处理时间为0ms”并告诉小mMessage一定要按时间顺序排队。进入队伍中,Looper正不辞辛劳的将一个个跟小mMessage一样的士兵带走。

public static void loop()

Run the message queue in this thread. Be sure to callquit() to end the loop.  

loop()方法有一个for死循环,不断调用queue.next()方法,在消息队列中取出Message。并在Message中取出target,这个target就是发送消息的mHandler调用它的dispatchMessage()方法。

首都的MessageQueue中心虽然message很多,但大家都按时间排着队,轮到mMessage了,Looper看了小mMessage的标签,对他说:“喔,又是mHandler带来的啊,那把你交给他处理了。”忐忑不安的小mMessage看到了一个熟悉的身影,mHandler,可能是接触太多Message,为了让mHandler想起自己,mMessage说出了上司教他的暗号0。

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

dispatchMessage()方法:若mCallback不为空,则调用mCallback的handleMessage();否则,直接调用Handler的handleMessage()方法,并将消息对象作为参数传递过去。在handleMessage()方法中,小mMessage出色的完成了任务。

简单使用代码在:https://github.com/HiSunny/ComeOnHandler.git


Thanks to  MeloDev、stromzhang

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/348738.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我们相信加密! 教程

许多人认为加密是一个复杂的主题&#xff0c;这很难理解。 虽然可以实现它的某些方面&#xff0c;但是每个人都可以理解它在更高层次上的工作方式。 这就是我要处理的这篇文章。 用简单的术语解释它是如何工作的&#xff0c;然后使用一些代码。 是的&#xff0c;我们信任加密…

使用Http协议访问网络--HttpURLConnection

public abstract classHttpURLConnection extends URLConnectionjava.lang.Object ↳java.net.URLConnection ↳java.net.HttpURLConnection 1、获取HttpURLConnection实例Protected ConstructorsHttpURLConnection(URL url)Constructs a new HttpURLConnection instance …

Spring Cloud –基本设置

Spring Cloud解决了分布式系统的常见问题。 但是&#xff0c;对于只使用广为人知的整体应用程序工作的人来说&#xff0c;从一开始就跳入一长串为分布式服务设计的模式可能会让人不知所措。 本文将通过实用的方法为您介绍Spring Cloud的基础知识。 完成后&#xff0c;您不仅应该…

Eclipse中的Tomcat:6个流行的“如何做”问题

学习新技术总是一个艰难的过程。 当您尝试学习将要相互交互的两种技术时&#xff0c;此过程变得更加困难。 Tomcat和Eclipse是Java EE开发中最流行的先决条件之一。 因此&#xff0c;要成为一名专业的开发人员&#xff0c;您需要知道如何使用此对执行最需要的操作以及如何进行一…

Spring Boot中带有CKEditor的AJAX

1.概述 在本文中&#xff0c;我们将介绍如何在Spring Boot中使用CKEditor 。 在本教程中&#xff0c;我们将导入一个包含大量数据的XML文档&#xff0c;对使用GET请求将一组数据加载到CKEditor实例的能力进行编程&#xff0c;并执行POST请求以保存CKEditor的数据。 我们将使用…

使用Http协议访问网络--HttpClient

public interface HttpClient org.apache.http.client.HttpClient HttpClient是Apache提供的Http网络访问接口。1、创建HttpClient实例HttpClient是一个接口&#xff0c;无法直接创建实例&#xff0c;通常创建一个DefaultHttpClient&#xff08;HttpClient 的SubClass&#xff…

编写测试用例

1、创建测试用例 为ComeOnBroadcastReceiverDo创建一个测试用例&#xff1a; 在导航栏File-->New-->Other 选择AndroidTestProject 2、点击next输入测试工程的name&#xff0c;选择测试工程路径 点击next,选择要测试的工程&#xff1a; 点击Finish完成测试工程的新建 被…

欢迎界面动画

实现一个欢迎界面的动画&#xff0c;即打开app显示的页面&#xff0c;动画结束后跳到Activity。 1、欢迎界面的背景是一个绿色矩形 <?xml version"1.0" encoding"utf-8"?> <shape xmlns:android"http://schemas.android.com/apk/res/andr…

动画机制与使用

Android3.0之前有两种动画&#xff0c;一种方式是补间动画 Tween Animation、另一种叫逐帧动画 Frame Animation&#xff08;也称Drawable Animation &#xff09;Android3.0以后增加了属性动画 Property Animation。Tween Animation、Frame Animation只能用于View&#xff0c;…

1、HTTP--Web's foundation

1、1 HTTP(HyperText Transfer Protocol)超文本传输协议----Internet的多媒体信使 1、2 Web客户端和服务器 Web内容都是存储在Web服务器上的&#xff0c;Web服务器使用的是HTTP协议&#xff0c;因此常被成为HTTP服务器。HTTP服务器和HTTP客户端共同构成World Wide Web的基本组…

IP地址分类及ISO-OSI、三次握手

1. A类地址A类地址的表示范围为&#xff1a;0.0.0.0~126.255.255.255(00000000~01111110)&#xff0c;最前面一位是“0”&#xff0c;用7位&#xff08;bit&#xff09;来标识网络号&#xff0c;24位标识主机号&#xff1b;默认网络掩码为&#xff1a;255.0.0.0&#xff0c;111…

drools 决策表_骆驼和春天的Drools决策表

drools 决策表正如我在之前的文章中所展示的那样&#xff0c; JBoss Drools是一个非常有用的规则引擎 。 唯一的问题是&#xff0c;对于非技术人员而言&#xff0c;以Rule语言创建规则可能会非常复杂。 这就是为什么人们可以提供一种简便的方法来创建业务规则-在电子表格中创建…

Thinking in Java方法签名

方法名和参数&#xff08;即&#xff0c;方法签名&#xff09;唯一标识某个方法&#xff1a;如&#xff0c; public void add(int a,int b){ } //这两个方法的方法签名一样&#xff0c;是不能在同一.java里的&#xff0c;编译通不过 public int add(int a,intb){ return a b; …

在Java中处理异常

每个程序员都希望编写一个完美的程序。 也就是说&#xff0c;程序运行时没有任何障碍。 好吧&#xff0c;如果希望是马&#xff0c;乞g就会骑。 除了程序员的所有愿望之外&#xff0c;有时还会发生无法预料的情况。 这些不可预见的情况在Java中通常被归类为“例外”。 异常会…

通信系统的组成

数字通信模型&#xff1a; http://blog.csdn.net/yaosiming2011/article/details/44280797 进程和线程

存储卡显示0字节怎么办?恢复0字节的存储小技巧

存储卡显示0字节是一个常见的故障现象&#xff0c;可能由多种原因引起。本文将详细分析存储卡出现此类问题的各种原因&#xff0c;并提供针对性的解决方法。通过深入了解这些原因和解决方案&#xff0c;读者可以有效地应对存储卡显示0字节的故障&#xff0c;从而恢复存储卡的正…

OSI模型和TCP/IP协议族

1、协议分层 两个实体之间要进行通信就需要有一个协议。而当通信比较复杂时就有必要将这个复杂的任务划分为多层&#xff0c;就需要有多个协议&#xff0c;每一层都有自己的协议。 2、ISO 国际标准化组织&#xff08;International Standard Organization &#xff0c; ISO&…

亚马逊s3的使用方法_使用jclouds库在Amazon S3上上传

亚马逊s3的使用方法在Java世界中&#xff0c;有几种很好的方法可以将内容上传到S3存储桶-在本文中&#xff0c;我们将研究jclouds库为此提供的功能。 要使用jclouds –特别是本文中讨论的API&#xff0c;应将此简单的Maven依赖项添加到项目的pom中&#xff1a; <dependency…

在PhotoShop中改像素m*n

快捷键&#xff1a;CtrlAlti&#xff0c;如图&#xff0c;改为28*28

Spring Boot Redis简介

1.概述 在本文中&#xff0c;我们将通过Spring Data Redis库回顾如何将Redis与Spring Boot结合使用的基础知识。 我们将构建一个应用程序&#xff0c;演示如何通过Web界面执行CRUD操作Redis 。 Github上提供了该项目的完整源代码。 2.什么是Redis&#xff1f; Redis是一个开源…