码迷,mamicode.com
首页 > 其他好文 > 详细

handler

时间:2015-03-01 10:18:37      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:

androidHandle类的主要作用:

1.在新启动的线程中发送消息

2.在主线程获取、处理消息


为什么要用Handle这样的一个机制:

因为在Android系统中UI操作并不是线程安全的,如果多个线程并发的去操作同一个组件,可能导致线程安全问题。为了解决这一个问题,android制定了一条规则:只允许UI线程来修改UI组件的属性等,也就是说必须单线程模型,这样导致如果在UI界面进行一个耗时叫长的数据更新等就会形成程序假死现象 也就是ANR异常,如果20秒中没有完成程序就会强制关闭。所以比如另一个线程要修改UI组件的时候,就需要借助Handler消息机制了。


Handle发送和处理消息的几个方法:

1. void handleMessage( Message msg):处理消息的方法,该方法通常被重写。

2.final boolean hasMessage(int what):检查消息队列中是否包含有what属性为指定值的消息

3.final boolean hasMessage(int what ,Object object) :检查消息队列中是否包含有whatobject属性指定值的消息

4.sendEmptyMessage(int what):发送空消息

5.final Boolean send EmptyMessageDelayed(int what ,long delayMillis):指定多少毫秒发送空消息

6.final boolean sendMessage(Message msg):立即发送消息

7.final boolean sendMessageDelayed(Message msg,long delayMillis):多少秒之后发送消息


Handle工作的几个组件LooperMessageQueue各自的作用:

1.Handler:它把消息发送给Looper管理的MessageQueue,并负责处理Looper分给它的消息

2.MessageQueue:采用先进的方式来管理Message

3.Looper:每个线程只有一个Looper,比如UI线程中,系统会默认的初始化一个Looper对象,它负责管理MessageQueue,不断的从MessageQueue中取消息,并将相对应的消息分给Handler处理


在线程中使用Handler的步骤:

1.调用Looperprepare()方法为当前线程创建Looper对象,创建Looper对象时,它的构造器会自动的创建相对应的MessageQueue

2.创建Handler子类的实例,重写HandleMessage()方法,该方法处理除UI线程以外线程的消息

3.调用Looperloop()方法来启动Looper

 

1. 申请一个Handler对象

Handler handler = new Handler();


2. 创建一个线程

{继承Thread类或者实现Runnable这个接口}

使用Runnable创建一个内部匿名类对象updateThread(要复写run方法)


3. 使用handlerpost方法将线程加入到线程队列中

handler.post(updateThread);


4. 使用handlerremoveCallbacks方法移出updateThread线程

注意:如果线程从线程队列中出来被执行后,则队列中就不在有线程


因此如果线程在被执行后没有方法将其再次加入到队列中,则无需使用removeCallbacks


线程走出线程队列有两种情况:

一种是被执行,此时要执行run方法

一种是使用removeCallbacks方法,此时线程不被执行,因此不调用run


5. 使用handlerpostDelayed方法延时将线程加入到队列中

handler.postDelayed(updateThread,3000)


注意:用post方法将线程对象放到队列里面执行,并没有开启一个新的线程,而是直接调用线程

对象的run方法,因此并没有实现线程的异步。


解决的办法是先生成一个HandlerThread对象,启动它(start

使用handlerThread对象的getLooper方法取得其looper对象,注意在此之前必须要start,否则这个looper是空的

并将looper对象作为参数传递给handler对象,使得这个handler对象绑定到这个Looper所在线程上面

此时需要重写handler类的构造函数,将looper对象传给父类


Looper:类,提供一种循环的从队列当中取得消息的功能,不要自己创建

这样,这个handler就可以循环的从Message消息队列中不断取消息。

 

Handler的作用

1.1发送和处理消息

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

private class MainHandler extends Handler {

public voidhandleMessage(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);


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++;

}}});}}

handler的消息发送与Post方法有什么区别呢?

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


1.3线程间通信

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

class MyThread extends Thread{

Handler mHandler;

Boolean boo;

publicMyThread(Handler handler){

mHandler = handler;

}

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

publid void run(){

if(boo){

getWeatherInfo();//耗时操作

analyzing();//耗时操作

mHandler.post(newRunnable() {

publicvoid run() {

setWeather();//更新UI

});//更新UI

boo = true;

}

}

}

在处理单击事件时:

sureButton.setOnClickListener(newButton.OnClickListener(){

public void onClick(View view){

setBoo(true);

myThread.start();

}

});


activity中:

MyThread myThread = new MyThread(mHandler);

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


2职责与关系

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

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

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

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

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

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


这样说来,多个Handler都可以共享同一LooperMessageQueue了。当然,这些Handler也就运行在同一个线程里。


Android的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper。事实上Android提供了一个封装好的带有looper的线程类,即为HandlerThread


3.不是所有的Handler都能更新UI

Handler处理消息总是在创建Handler的线程里运行。而我们的消息处理中,不乏更新UI的操作,不正确的线程直接更新UI将引发异常。因此,需要时刻关心Handler在哪个线程里创建的。如何更新UI才能不出异常呢?SDK告诉我们,有以下4种方式可以从其它线程访问UI线程(也即线程间通信)

Activity.runOnUiThread(Runnable)

View.post(Runnable)

View.postDelayed(Runnable, long)

UI线程中创建的Handler


其中,重点说一下的是View.post(Runnable)方法。在post(Runnableaction)方法里,View获得当前线程(即UI线程)的Handler,然后将action对象postHandler里。在Handler里,它将传递过来的action对象包装成一个MessageMessagecallbackaction),然后将其投入UI线程的消息循环中。在 Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnablerun方法。而此时,已经路由到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();之后就进入了消息循环,这个之后就可以发消息、取消息、和处理消息。


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


public class HandlerThreadActivity extends Activity {

private static final String TAG = "HandlerThreadActivity";

private HandlerThread mHandlerThread;

private MyHandler mMyHandler;


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);


TextView text = new TextView(this);

text.setText("HandlerThreadActivity");

setContentView(text);


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

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

mHandlerThread = new HandlerThread("handler_thread");


//在使用HandlerThreadgetLooper()方法之前,必须先调用该类的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) {

super.handleMessage(msg);

}

}

}

handler

标签:

原文地址:http://www.cnblogs.com/lin-lin/p/4306590.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!