1.什么是Handler?

SDK中关于Handler的说明例如以下:

A Handler allows you to sendand process Messageand Runnable objects associated with a thread's
MessageQueue.Each Handler instance is associated with a single thread and that thread'smessage 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 willdeliver messages and runnables to that message queue and execute them as theycome out of the message queue.

1.1Handler的作用

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

1.1.1发送和处理消息

以下的代码对于我们来说又是多么的常见:

首先在Activity中创建一个继承自Handler的匿名内部类以及这个类的一个对象

Private MainHandler mMainHandler = new MainHandler();

private
class
MainHandler extends Handler {

public
void
handleMessage(android.os.Message msg) {

switch (msg.what) {

case
MSG_MAIN_HANDLER_TEST
:

Log.d(TAG,
"MainHandler-->handleMessage-->thread id =" +     Thread.currentThread().getId());

break;

}

}

};

这样在Activity的其它地方就能够通过mMainHandler对象发送消息给Handler处理了

Message msg = mMainHandler.obtainMessage(MSG_MAIN_HANDLER_TEST);

mMainHandler.sendMessage(msg);

【疑问】这里的消息是如何交给handler处理的,另外当有多个消息的时候处理的先后顺序呢?(以下会进行解答)

1.1.2处理runnables方法中的代码

除了上述的使用Handler发送以及处理消息外,handler另一个作用就是处理传递给它的action对象,详细使用步骤演示样例:

1、在主线程中定义Handler对象

2、构造一个runnable对象,为该对象实现runnable方法。

3、在子线程中使用Handler对象post(runnable)对象.

handler.post这个函数的作用是把Runnable里面的run方法里面的这段代码发送到消息队列中,等待执行。

假设handler是以UI线程消息队列为參数构造的,那么是把run里面的代码发送到UI线程中,等待UI线程执行这段代码。

假设handler是以子线程线程消息队列为參数构造的,那么是把run里面的代码发送到子线程中,等待子线程执行这段代码。

Runnable 并不一定是新开一个线程,比方以下的代码中就是执行在UI主线程中的:

public
class
TestActivity extends Activity
implementsOnClickListener {

/** Calledwhen the activity is first created. */

private Button
mBtnTest=null;

private Handler
myHandler=null;

@Override

public
void
onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

mBtnTest=(Button)findViewById(R.id.btn_test);

mBtnTest.setOnClickListener(this);

myHandler=new Handler();

}

@Override

public
void
onClick(View v) {

 //注意:此处UI线程被堵塞,由于myHandler是在UI线程中创建的

myHandler.post(new Runnable() {

public
void
run() {

long i=0;

while(true){

i++;

}

}

});

}

}

官方对这种方法的解释例如以下,注意当中的:“The runnable will be run on the userinterface thread. ”

booleanandroid.view.View .post(Runnable action)

Causes the Runnableto be added to the message queue. The runnable will be run on the userinterface thread.

Parameters:

action The Runnablethat will be executed.

Returns:

Returns true if theRunnable was successfully placed in to the message queue. Returns false onfailure, usually because the looper processing the message queue is exiting.

这里我们看代码 mHandler.post(new Runnable(){  好像是new 了一个 interface, 事实上是new的一个实现Runnable的匿名内部类(Inner Anonymous Class),这是非常简练的写法。

上面的代码能够看成是: new anonymousClass() implement interface{ [改写interface method]}

Runnable是一个接口,不是一个线程,一般线程会实现Runnable。所以假设我们使用匿名内部类是执行在UI主线程的,假设我们使用实现这个Runnable接口的线程类,则是执行在相应线程的。

【疑问】handler的消息发送与Post方法有什么差别呢?

Handler对象消息发送sendXXXX相关方法例如以下,同一时候还有postXXXX相关方法, 这些和Win32中的道理基本一致,一个为发送后直接返回,一个为处理后才返回。

1.1.3线程间通信

以下代码中红色标注处即为在MyThread这个线程中,通过UI线程中的handler向UI线程发送消息。

定义一个线程

class MyThread extends Thread{

Handler   mHandler;

Boolean  boo;

publicMyThread(Handler handler){

mHandler = handler;

}

publicvoid setBoo(boolean b) {boo = b; }

publidvoid run(){

if(boo){

getWeatherInfo();//耗时操作

analyzing();//耗时操作

                                                        mHandler.post(newRunnable() {

                                                                                                              publicvoid run() {

                                       setWeather();//更新UI

                                        });//更新UI

boo = true;

}

}

}

在处理单击事件时:

sureButton.setOnClickListener(newButton.OnClickListener(){

publicvoid onClick(View view){

setBoo(true);

myThread.start();

}

});

在activity中:

MyThread myThread = new MyThread(mHandler);

当中mHandler为在UI线程中创建的。

1.2职责与关系

熟悉Windows编程的朋友可能知道Windows程序是消息驱动的,而且有全局的消息循环系统。而Android应用程序也是消息驱动的,按道理来说也应该提供消息循环机制。实际上谷歌參考了Windows的消息循环机制,也在Android系统中实现了消息循环机制。
Android通过Looper、Handler来实现消息循环机制,Android消息循环是针对线程的(每一个线程都能够有自己的消息队列和消息循环)。

什么是looper?以下就简单的介绍下各个对象的职责:

Message:消息,当中包括了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。

Handler:处理者,负责Message的发送及处理。使用Handler时,须要实现handleMessage(Messagemsg)方法来对特定的Message进行处理,比如更新UI等。

MessageQueue:消息队列,用来存放Handler发送过来的消息,并依照FIFO规则运行。当然,存放Message并不是实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。

Looper:消息泵,不断地从MessageQueue中抽取Message运行。因此,一个MessageQueue须要一个Looper。

Thread:线程,负责调度整个消息循环,即消息循环的运行场所。

Handler,Looper和MessageQueue就是简单的三角关系。Looper和MessageQueue一一相应,创建一个
Looper的同一时候,会创建一个MessageQueue。而Handler与它们的关系,仅仅是简单的聚集关系,即Handler里会引用当前线程里的特定Looper和MessageQueue。

这样说来,多个Handler都能够共享同一Looper和MessageQueue了。当然,这些Handler也就执行在同一个线程里。

【疑问】我们写的Activity中没有看见looper,也没有看见什么Thread去调度整个消息循环?

Activity是一个UI线程,执行于主线程中,Android系统在启动的时候会为Activity创建一个消息队列和消息循环(Looper),具体实现请參考ActivityThread.java文件。

1.3怎样实现消息的发送与处理

接下来,我们简单地看一下消息的循环过程:

1.3.1消息的生成

Message msg =mHandler.obtainMessage();

msg.what = what;

msg.sendToTarget();

1.3.2消息的发送

MessageQueue queue= mQueue;

if (queue != null){

msg.target =this;

sent =queue.enqueueMessage(msg, uptimeMillis);

}

在Handler.java的sendMessageAtTime(Messagemsg, long uptimeMillis)方法中,我们看到,它找到它所引用的MessageQueue,然后将Message的target设定成自己(目的是为了在处理消息环节,Message能找到正确的Handler),再将这个Message纳入到消息队列中。

1.3.3消息的抽取

Looper me =myLooper();

MessageQueue queue= me.mQueue;

while (true) {

Message msg =queue.next(); // might block

if (msg !=null) {

if(msg.target == null) {

// Notarget is a magic identifier for the quit message.

return;

}

msg.target.dispatchMessage(msg);

msg.recycle();

}

}

在Looper.java的loop()函数里,我们看到,这里有一个死循环,不断地从MessageQueue中获取下一个(next方法)Message,然后通过Message中携带的target信息,交由正确的Handler处理(dispatchMessage方法)。

1.3.4消息的处理

if (msg.callback!= null) {

handleCallback(msg);

} else {

if (mCallback!= null) {

if(mCallback.handleMessage(msg)) {

return;

}

}

handleMessage(msg);

}

在Handler.java的dispatchMessage(Messagemsg)方法里,当中的一个分支就是调用handleMessage方法来处理这条Message,而这也正是我们在职责处描写叙述使用Handler时须要实现handleMessage(Messagemsg)的原因。

至于dispatchMessage方法中的另外一个分支,我将会在后面的内容中说明。

至此,我们看到,一个Message经由Handler的发送,MessageQueue的入队,Looper的抽取,又再一次地回到Handler的怀抱。而绕的这一圈,也正好帮助我们将同步操作变成了异步操作。

1.4在工作线程(WorkerThread)中使用Handler

【疑问】上面介绍了怎样在主线程中使用handler以及handler发送和处理消息的详细原理,而且SDK中已经提到能够在自己定义的线程中使用对应的handler来处理消息,这个怎样实现呢?

通用的作法是:

class LooperThreadextends Thread {

publicHandler mHandler;

publicvoid run() {

Looper.prepare();

mHandler= new Handler() {

public void handleMessage(Message msg) {

// process incoming messages here

}

};

Looper.loop();   //不能在这个后面加入�代码,程序是无法执行到这行之后的

}

}

在创建Handler之前,为该线程准备好一个Looper(Looper.prepare),然后让这个Looper跑起来(Looper.loop),抽取Message,这样,Handler才干正常工作。

1.5不是全部的Handler都能更新UI

种方式能够从其他线程訪问UI线程(也即线程间通信):

·      Activity.runOnUiThread(Runnable)

·      View.post(Runnable)

·      View.postDelayed(Runnable, long)

·      在UI线程中创建的Handler

当中,重点说一下的是View.post(Runnable)方法。在post(Runnableaction)方法里,View获得当前线程(即UI线程)的Handler,然后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),然后将其投入UI线程的消息循环中。在
Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法。而此时,已经路由到UI线程里,因此,我们能够毫无顾虑的来更新UI。

几点小结

·      Handler的处理过程执行在创建Handler的线程里

·      一个Looper相应一个MessageQueue,一个线程相应一个Looper,一个Looper能够相应多个Handler

·      不确定当前线程时,更新UI时尽量调用View.post方法

·      handler应该由处理消息的线程创建。

·      handler与创建它的线程相关联,并且也仅仅与创建它的线程相关联。handler执行在创建它的线程中,所以,假设在handler中进行耗时的操作,会堵塞创建它的线程。

·      Android的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper。主线程(UI线程)就是一个消息循环的线程。

·      Looper.myLooper();      //获得当前的Looper

Looper.getMainLooper() //获得UI线程的Lopper

·      Handle的初始化函数(构造函数),假设没有參数,那么他就默认使用的是当前的Looper,假设有Looper參数,就是用相应的线程的Looper。

·      假设一个线程中调用Looper.prepare(),那么系统就会自己主动的为该线程建立一个消息队列,然后调用Looper.loop();之后就进入了消息循环,这个之后就能够发消息、取消息、和处理消息。

2.HandlerThread

在上面的总结中指出,Android的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper。其实Android提供了一个封装好的带有looper的线程类,即为HandlerThread,详细可參见以下的代码:

public
class
HandlerThreadActivity extends Activity {

private
static final
String TAG =
"HandlerThreadActivity";

private
HandlerThreadmHandlerThread;

private MyHandler
mMyHandler;

@Override

protected
void
onCreate(Bundle savedInstanceState) {

// TODO Auto-generatedmethod stub

super.onCreate(savedInstanceState);

TextView text = new TextView(this);

text.setText("HandlerThreadActivity");

setContentView(text);

Log.d(TAG,
"The mainthread id = " +      Thread.currentThread().getId());

//生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能,

//这个类由Android应用程序框架提供

mHandlerThread =
new
HandlerThread("handler_thread");

//在使用HandlerThread的getLooper()方法之前,必须先调用该类的start();

mHandlerThread.start();

//即这个Handler是执行在mHandlerThread这个线程中

mMyHandler = new MyHandler(mHandlerThread.getLooper());

mMyHandler.sendEmptyMessage(1);

}

private
class
MyHandler extends Handler {

public MyHandler(Looper looper) {

super(looper);

}

@Override

public
void
handleMessage(Message msg) {

Log.d(TAG,
"MyHandler-->handleMessage-->threadid = " + Thread.currentThread().getId());

super.handleMessage(msg);

}

}

}

Handler和HandlerThread的更多相关文章

  1. Android Handler,Loop,HandlerThread消息处理

    博客标题也不知道写什么好,仅仅是近期有时候发现Handler,Loop,HandlerThread非常easy混淆,所以做了简单的笔记处理: 第一种 : 大概的意思给出说明图: watermark/2 ...

  2. Handler,Looper,HandlerThread浅析

    Handler想必在大家写Android代码过程中已经运用得炉火纯青,特别是在做阻塞操作线程到UI线程的更新上.Handler用得恰当,能防止很多多线程异常. 而Looper大家也肯定有接触过,只不过 ...

  3. 安卓权威编程指南-笔记(第24章 Looper Handler 和 HandlerThread)

    AsyncTask是执行后台线程的最简单方式,但它不适用于那些重复且长时间运行的任务. 1. Looper Android中,线程拥有一个消息队列(message queue),使用消息队列的线程叫做 ...

  4. 昨天刚看了Handler和HandlerThread这个东西,不明白为什么要用这么复杂的东西,而且Handler直接post的话好像还不是子线程运行。那我再开发的时候直接用Thread行不行?两个有什么区别?

    Handler就是android中一个机制,主要是考虑到线程安全的! Handler是可以实现线程间通信的,LZ知道Android的UI线程不安全的吧,也就是说不可以在UI线程以外的其他线程对UI进行 ...

  5. Handler 原理分析和使用之HandlerThread

    前面已经提到过Handler的原理以及Handler的三种用法.这里做一个非常简单的一个总结: Handler 是跨线程的Message处理.负责把Message推送到MessageQueue和处理. ...

  6. Android---组件篇---Handler的使用(1)[转]

    在android中,有很多功能是不能放在onCreate或者onStart方法里面,因为这些功能相对 来说费时比较长,比如说下载一个文件,下载的过程比较长,但是如果写在Activity中, 那么这段时 ...

  7. android 进程/线程管理(三)----Thread,Looper / HandlerThread / IntentService

    Thread,Looper的组合是非常常见的组合方式. Looper可以是和线程绑定的,或者是main looper的一个引用. 下面看看具体app层的使用. 首先定义thread: package ...

  8. Android(java)学习笔记265:Android线程形态之 HandlerThread

    1.  HandlerThread Android HandlerThread 完全解析 Handler与HandlerThread区别,HandlerThread应用(对比AsyncTask) 备注 ...

  9. handler.post 为什么要将thread对象post到handler中执行呢?

    转载网址:http://www.cnblogs.com/crazypebble/archive/2011/03/23/1991829.html在Android中使用Handler和Thread线程执行 ...

随机推荐

  1. Search a 2D Matrix【python】

    class Solution: # @param matrix, a list of lists of integers # @param target, an integer # @return a ...

  2. [置顶] android 自定义TextView

    系统自带的控件TextView有时候没满一行就换行了,为了解决这个问题,自定义了一个TextView,只有一行显示不完全的情况下才会去换行显示,代码如下: package com.open.textv ...

  3. linux c setitimer使用方法说明

    在linux c编程中.setitimer是一个比較经常使用的函数.可用来实现延时和定时的功能,网上有各种零零散散的使用方法说明,都仅仅提到了个别使用方法,今天抽出时间实践整理了一份比較具体的: 使用 ...

  4. (1)ActivityThread分析

    1. 入口. 曾经一直都说Activity的人口是onCreate方法.事实上android上一个应用的入口,应该是ActivityThread.和普通的java类一样,入口是一个main方法. pu ...

  5. 圣魔大战3(Castle Fantisia)艾伦希亚战记完美攻略

    作为城堡幻想曲系列续作,艾伦希亚战记继承了前作的战棋+养成模式进行游戏. (城堡幻想曲3,纠正大家个错误哦,不是圣魔大战3,圣魔大战是城堡幻想曲2,圣魔大战不是个系列,艾伦西亚战记==艾伦希亚战记,一 ...

  6. fcntl()

      fcntl() F_GETFL---------------------------------------------        将文件状态标志作为函数值返回. 文件状态标志:        ...

  7. Project configuration is not up-to-date with pom.xml错误解决方法

    导入一个Maven项目之后发现有一个如下的错误: Project configuration is not up-to-date with pom.xml. Run project configura ...

  8. 一起C语言中程序时序问题的排查过程

    [文章摘要] 对于由多个模块协同工作的软件来说,程序处理的时序是很重要的.当消息处理的顺序出现混乱时,程序就会出现异常. 本文基于作者的实际项目经验.对软件模块之间的时序问题进行了具体的分析,为相关软 ...

  9. 用WebCollector制作一个爬取《知乎》并进行问题精准抽取的爬虫(JAVA)

    简单介绍: WebCollector是一个无须配置.便于二次开发的JAVA爬虫框架(内核),它提供精简的的API.仅仅需少量代码就可以实现一个功能强大的爬虫. 怎样将WebCollector导入项目请 ...

  10. EasyUI - DataGrid 组建 - [ 排序功能 ]

    效果: 红框的字段看,为设置了,列排序,向后台Post数据sort/order. 原理:向后台POST数据,sort/post数据. html代码: <table id="tab&qu ...