Handler Looper Message(一)

来源:互联网 发布:数据访问层框架 编辑:程序博客网 时间:2024/05/20 06:52

(一)初步认识



1)、大致的了解是这样的:


1、Message 就是消息(包括消息体本身  和  消息的一些其他属性)

2、Handler 是消息的发送和接受者(当然是相对于两个 **  而言),还用来读取执行Message

3、Looper 内部维护一个 MessageQueue 这是一个队列 用于存放自己的Handler 接受到 的 Message


2)、看下API吧:


1、Message:


android.os.Message


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.


While the constructor of Message is public, the best way to get one of these is to callMessage.obtain() or one of theHandler.obtainMessage() methods, which will pull them from a pool of recycled objects.


翻译:


定义一个Message它可以包含对任意 data object(数据对象)的描述,这个Message可以被发送给 一个Handler。

这个Message对象包含两个的 int 数据 和一个 object 数据(即任意类型的数据都可以 以Message为载体进行传送), that allow you to not do allocations in many cases. (<这句话不太理解,之一就是:>让你在很多情况下不用做分配。)——应该是:免去了字节对数据进行包装的麻烦。就是说这个类很方便。


2、Handler


android.os.Handler


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.


There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.


Scheduling messages is accomplished with the post,postAtTime(Runnable, long),postDelayed,sendEmptyMessage,sendMessage,sendMessageAtTime, andsendMessageDelayed methods. Thepost versions allow you to enqueue Runnable objects to be called by the message queue when they are received; thesendMessage versions allow you to enqueue a Message object containing a bundle of data that will be processed by the Handler'shandleMessage method (requiring that you implement a subclass of Handler).


When posting or sending to a Handler, you can either allow the item to be processed as soon as the message queue is ready to do so, or specify a delay before it gets processed or absolute time for it to be processed. The latter two allow you to implement timeouts, ticks, and other timing-based behavior.


When a process is created for your application, its main thread is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. You can create your own threads, and communicate back with the main application thread through a Handler. This is done by calling the samepost orsendMessage methods as before, but from your new thread. The given Runnable or Message will then be scheduled in the Handler's message queue and processed when appropriate.


翻译:


一个Handler 允许你发送/处理 和当前线程的MessageQueue(消息队列)相关联的Message 和 Runnable 对象。每一个Handler实例都 与 单一的Thread(线程)和线程的MessageQueue 相关联。(补充一句Handler和Thread是 <多对1>关系——一个Thread中允许有多个Handler、、但是只能有一个Looper)当你创建了一个新的Handler时这个Handler对象就会和创建它的 Thread/MessageQueue 绑定——从这时起,它(就是Handler对象)就会发送 Message 和 Runnables 给别的线程,并且执行来自自身 的MessageQueue 中的指令。


Handler的两个主要用途:

a、安排 Message 和 Runnable 被执行的时间。

b、在其他线程中加入本线程想要执行的操作。


通过post(Runnble),postAtTime(Runnable, long),postDelayed,sendEmptyMessage,sendMessage,sendMessageAtTime, andsendMessageDelayed这些方法 使得 Message 被实现。The post versions allow you to enqueue Runnable objects to be called by the message queue  when they are received;<不太理解>当they are recived通过message queue调用post(Runnble)方法允许你把Runnble对象 enqueue(入队);

sendMessage(Message msg)方法允许你enqueue(入队)包含Bundle数据的Message 对象。这个对象将由Handler类的handleMessage(Message msg) 方法处理(这需要你实现一个Handler的子类).


当发送或接受一个Handler消息时,如果MessageQueue允许的话,你可以要求立刻处理这个Message 或 指定延迟执行 或 延迟你指定的时间后执行。 后两个选择允许你 implement(复写) timeouts、ticks、和其他基于时序的 method。


<最后一段并不是很理解>当为你的应用创建一个进程的时候,主线程专注于处理 关心顶级应用程序对象(activities, broadcast receivers,等)以及这些对象创建的windows 的message queue(消息队列)。

你可以创建自己的线程,并通过 一个 Handler 和应用程序的主线程进行通信。

这么做是同样是通过调用 post(Runnble)、sendMessage(Message msg)方法,不同的是通过自己的线程调用。发送过来的 Runnable或Message 将被Handler的MessageQueue调度,当合适的时候会被执行。


3、Looper


android.os.Looper


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 theHandler class.


This is a typical example of the implementation of a Looper thread, using the separation ofprepare andloop to create an initial Handler to communicate with the Looper.

<pre name="code" class="java">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();      }  }


</pre>

翻译:


此类是运行一个线程message loop(消息循环)。线程在默认情况下没有关联的message loop(消息循环);通过在线程中调用voidandroid.os.Looper.prepare()方法将当前线程初始化为Looper线程,然后voidandroid.os.Looper.loop()开始处理Messages(消息)直到循环结束。

Looper类大部分与Message Loop 进行的交互是通过 Handler 类实现的。


那段代码是实现 Looper线程 的一个典型的例子,分别使用 void android.os.Looper.prepare() 和 void.android.os.Looper.loop() 去创建并初始化一个 Handler 实例,通过这个Handler 和Looper进行通信。



其实看完 API 也并没有理解什么。不论如何,接下来该实际的搞一搞了。

先看看:http://www.cnblogs.com/codingmyworld/archive/2011/09/14/2174255.html————这个学长可是碉堡了
接下来全文复制:


android的消息处理机制(图+源码分析)——Looper,Handler,Message

作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想。android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种helper类,对于和我一样渴望水平得到进阶的人来说,都太值得一读了。这不,前几天为了了解android的消息处理机制,我看了Looper,Handler,Message这几个类的源码,结果又一次被googler的设计震撼了,特与大家分享。

android的消息处理有三个核心类:Looper,Handler和Message。其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因此我没将其作为核心类。下面一一介绍:

线程的魔法师 Looper

Looper的字面意思是“循环者”,它被设计用来使一个普通线程变成Looper线程。所谓Looper线程就是循环工作的线程。在程序开发中(尤其是GUI开发中),我们经常会需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务,这就是Looper线程。使用Looper类创建Looper线程很简单:

复制代码
public class LooperThread extends Thread {
@Override
public void run() {
// 将当前线程初始化为Looper线程
Looper.prepare();

// ...其他处理,如实例化handler

// 开始循环处理消息队列
Looper.loop();
}
}
复制代码

通过上面两行核心代码,你的线程就升级为Looper线程了!!!是不是很神奇?让我们放慢镜头,看看这两行代码各自做了什么。

1)Looper.prepare()

通过上图可以看到,现在你的线程中有一个Looper对象,它的内部维护了一个消息队列MQ。注意,一个Thread只能有一个Looper对象,为什么呢?咱们来看源码。

复制代码
public class Looper {
// 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象
private static final ThreadLocal sThreadLocal = new ThreadLocal();
// Looper内的消息队列
final MessageQueue mQueue;
// 当前线程
Thread mThread;
// 。。。其他属性

// 每个Looper对象中有它的消息队列,和它所属的线程
private Looper() {
mQueue
= new MessageQueue();
mRun
= true;
mThread
= Thread.currentThread();
}

// 我们调用该方法会在调用线程的TLS中创建Looper对象
public static final void prepare() {
if (sThreadLocal.get() != null) {
// 试图在有Looper的线程中再次创建Looper将抛出异常
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(
new Looper());
}
// 其他方法
}
复制代码

通过源码,prepare()背后的工作方式一目了然,其核心就是将looper对象定义为ThreadLocal。如果你还不清楚什么是ThreadLocal,请参考《理解ThreadLocal》。

2)Looper.loop()

调用loop方法后,Looper线程就开始真正工作了,它不断从自己的MQ中取出队头的消息(也叫任务)执行。其源码分析如下:

复制代码
  public static final void loop() {
Looper me
= myLooper(); //得到当前线程Looper
MessageQueue queue = me.mQueue; //得到当前looper的MQ

// 这两行没看懂= = 不过不影响理解
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// 开始循环
while (true) {
Message msg
= queue.next(); // 取出message
if (msg != null) {
if (msg.target == null) {
// message没有target为结束信号,退出循环
return;
}
// 日志。。。
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
// 非常重要!将真正的处理工作交给message的target,即后面要讲的handler
msg.target.dispatchMessage(msg);
// 还是日志。。。
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);

// 下面没看懂,同样不影响理解
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);
}
// 回收message资源
msg.recycle();
}
}
}
复制代码

除了prepare()和loop()方法,Looper类还提供了一些有用的方法,比如

Looper.myLooper()得到当前线程looper对象:

    public static final Looper myLooper() {
// 在任意线程调用Looper.myLooper()返回的都是那个线程的looper
return (Looper)sThreadLocal.get();
}

getThread()得到looper对象所属线程:

    public Thread getThread() {
return mThread;
}

quit()方法结束looper循环:

    public void quit() {
// 创建一个空的message,它的target为NULL,表示结束循环消息
Message msg = Message.obtain();
// 发出消息
mQueue.enqueueMessage(msg, 0);
}

到此为止,你应该对Looper有了基本的了解,总结几点:

1.每个线程有且最多只能有一个Looper对象,它是一个ThreadLocal

2.Looper内部有一个消息队列,loop()方法调用后线程开始不断从队列中取出消息执行

3.Looper使一个线程变成Looper线程。

那么,我们如何往MQ上添加消息呢?下面有请Handler!(掌声~~~)

异步处理大师 Handler

什么是handler?handler扮演了往MQ上添加消息和处理消息的角色(只处理由自己发出的消息),即通知MQ它要执行一个任务(sendMessage),并在loop到自己的时候执行该任务(handleMessage),整个过程是异步的。handler创建时会关联一个looper,默认的构造方法将关联当前线程的looper,不过这也是可以set的。默认的构造方法:

复制代码
public class handler {

final MessageQueue mQueue; // 关联的MQ
final Looper mLooper; // 关联的looper
final Callback mCallback;
// 其他属性

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());
}
}
// 默认将关联当前线程的looper
mLooper = Looper.myLooper();
// looper不能为空,即该默认的构造方法只能在looper线程中使用
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
// 重要!!!直接把关联looper的MQ作为自己的MQ,因此它的消息将发送到关联looper的MQ上
mQueue = mLooper.mQueue;
mCallback
= null;
}

// 其他方法
}
复制代码

下面我们就可以为之前的LooperThread类加入Handler:

复制代码
public class LooperThread extends Thread {
private Handler handler1;
private Handler handler2;

@Override
public void run() {
// 将当前线程初始化为Looper线程
Looper.prepare();

// 实例化两个handler
handler1 = new Handler();
handler2
= new Handler();

// 开始循环处理消息队列
Looper.loop();
}
}
复制代码

加入handler后的效果如下图:

可以看到,一个线程可以有多个Handler,但是只能有一个Looper!

Handler发送消息

有了handler之后,我们就可以使用 post(Runnable)postAtTime(Runnable, long)postDelayed(Runnable, long)sendEmptyMessage(int)sendMessage(Message)sendMessageAtTime(Message, long)和 sendMessageDelayed(Message, long)这些方法向MQ上发送消息了。光看这些API你可能会觉得handler能发两种消息,一种是Runnable对象,一种是message对象,这是直观的理解,但其实post发出的Runnable对象最后都被封装成message对象了,见源码:

复制代码
    // 此方法用于向关联的MQ上发送Runnable对象,它的run方法将在handler关联的looper线程中执行
public final boolean post(Runnable r)
{
// 注意getPostMessage(r)将runnable封装成message
return sendMessageDelayed(getPostMessage(r), 0);
}

private final Message getPostMessage(Runnable r) {
Message m
= Message.obtain(); //得到空的message
m.callback = r; //将runnable设为message的callback,
return m;
}

public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue
= mQueue;
if (queue != null) {
msg.target
= this; // message的target必须设为该handler!
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e
= new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w(
"Looper", e.getMessage(), e);
}
return sent;
}
复制代码

其他方法就不罗列了,总之通过handler发出的message有如下特点:

1.message.target为该handler对象,这确保了looper执行到该message时能找到处理它的handler,即loop()方法中的关键代码

msg.target.dispatchMessage(msg);

2.post发出的message,其callback为Runnable对象

Handler处理消息

说完了消息的发送,再来看下handler如何处理消息。消息的处理是通过核心方法dispatchMessage(Message msg)与钩子方法handleMessage(Message msg)完成的,见源码

复制代码
    // 处理消息,该方法由looper调用
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 如果message设置了callback,即runnable消息,处理callback!
handleCallback(msg);
}
else {
// 如果handler本身设置了callback,则执行callback
if (mCallback != null) {
/* 这种方法允许让activity等来实现Handler.Callback接口,避免了自己编写handler重写handleMessage方法。见http://alex-yang-xiansoftware-com.iteye.com/blog/850865 */
if (mCallback.handleMessage(msg)) {
return;
}
}
// 如果message没有callback,则调用handler的钩子方法handleMessage
handleMessage(msg);
}
}

// 处理runnable消息
private final void handleCallback(Message message) {
message.callback.run();
//直接调用run方法!
}
// 由子类实现的钩子方法
public void handleMessage(Message msg) {
}
复制代码

可以看到,除了handleMessage(Message msg)和Runnable对象的run方法由开发者实现外(实现具体逻辑),handler的内部工作机制对开发者是透明的。这正是handler API设计的精妙之处!

Handler的用处

我在小标题中将handler描述为“异步处理大师”,这归功于Handler拥有下面两个重要的特点:

1.handler可以在任意线程发送消息,这些消息会被添加到关联的MQ上。

              

2.handler是在它关联的looper线程中处理消息的。

这就解决了android最经典的不能在其他非主线程中更新UI的问题。android的主线程也是一个looper线程(looper在android中运用很广),我们在其中创建的handler默认将关联主线程MQ。因此,利用handler的一个solution就是在activity中创建handler并将其引用传递给worker thread,worker thread执行完任务后使用handler发送消息通知activity更新UI。(过程如图)

下面给出sample代码,仅供参考:

复制代码
public class TestDriverActivity extends Activity {
private TextView textview;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textview
= (TextView) findViewById(R.id.textview);
// 创建并启动工作线程
Thread workerThread = new Thread(new SampleTask(new MyHandler()));
workerThread.start();
}

public void appendText(String msg) {
textview.setText(textview.getText()
+ "\n" + msg);
}

class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
String result
= msg.getData().getString("message");
// 更新UI
appendText(result);
}
}
}
复制代码
复制代码
public class SampleTask implements Runnable {
private static final String TAG = SampleTask.class.getSimpleName();
Handler handler;

public SampleTask(Handler handler) {
super();
this.handler = handler;
}

@Override
public void run() {
try { // 模拟执行某项任务,下载等
Thread.sleep(5000);
// 任务完成后通知activity更新UI
Message msg = prepareMessage("task completed!");
// message将被添加到主线程的MQ中
handler.sendMessage(msg);
}
catch (InterruptedException e) {
Log.d(TAG,
"interrupted!");
}

}

private Message prepareMessage(String str) {
Message result
= handler.obtainMessage();
Bundle data
= new Bundle();
data.putString(
"message", str);
result.setData(data);
return result;
}

}
复制代码

当然,handler能做的远远不仅如此,由于它能post Runnable对象,它还能与Looper配合实现经典的Pipeline Thread(流水线线程)模式。请参考此文《Android Guts: Intro to Loopers and Handlers》

封装任务 Message

在整个消息处理机制中,message又叫task,封装了任务携带的信息和处理该任务的handler。message的用法比较简单,这里不做总结了。但是有这么几点需要注意(待补充):

1.尽管Message有public的默认构造方法,但是你应该通过Message.obtain()来从消息池中获得空消息对象,以节省资源。

2.如果你的message只需要携带简单的int信息,请优先使用Message.arg1和Message.arg2来传递信息,这比用Bundle更省内存

3.擅用message.what来标识信息,以便用不同方式处理message。





参考:

http://blog.csdn.net/dadoneo/article/details/7667726

http://blog.csdn.net/yuzhiboyi/article/details/7562245

http://blog.csdn.net/caesardadi/article/details/8473777——————还有方法的中文API 值得看看



http://www.cnblogs.com/codingmyworld/archive/2011/09/14/2174255.html————这个学长可是碉堡了


0 0
原创粉丝点击