Handler机制的简单原理
因为android UI界面不是线程安全的,不允许子线程更新主UI线程,为了达到主界面的更新操作,此时便有了Handler对象.
Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。Android利用Handler来实现UI线程的更新的。
Handler是Android中的消息发送器,其在哪个Activity中创建就属于且紧紧属于该Activity。还可以说其在哪个线程中new的,就是那个线程的Handler。
Handler的定义: 主要接受子线程发送的数据, 并用此数据配合主线程更新UI.
在UI线程:
handler对象首先在主界面中进行声明,并覆盖其中的handleMessage(msg)方法。该方法用来接收子线程传递来的Message对象。
在子线程:
子线程启动后,首先创建Message对象。然后将待发送的数据放入Message对象中,并使用handler的sendMessage(msg)来发送msg对象,发送成功够,handleMessage(msg)拿到msg对象,并用这个msg对象里面的数据 来在主线程中更新手机界面。
Handler特点 :
handler可以分发Message对象和Runnable对象到主线程中,每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),
它有两个作用:
(1)安排消息或Runnable在某个主线程中某个地方执行
(2)安排一个动作在不同的线程中执行
Handler中分发消息的一些方法 :
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
sendMessage类方法,允许你安排一个带数据的Message对象到队列中,等待更新.
比如看看一般欢迎界面的实现方法:
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
public class WelcomeScreen extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.welcome_screen);
Handler handler = new Handler();
handler.postDelayed(new Loading(), 2000);//2s后执行Loading线程, 跳转到MainActivity
}
class Loading implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
startActivity(new Intent(WelcomeScreen.this,MainActivity.class));
WelcomeScreen.this.finish();
}
}
}
补充别人总结的:
1、向哪个Handler发送消息,就必须在哪个handler里面接收;
2、直接使用JAVA的 Thread是无法更新Android UI的,因为Android View在设计的时线程是不完全的,不过Android提供了几种供开发者在线程中更新UI的方法,如下:
runOnUiThread( Runnable )
post( Runnable )
postDelayed( Runnable, long )
3、直接使用hanlder.post等方法是在当前主线程里面做操作,而不是另外新建线程,建议使用Thread线程直接新建另外一个线程或者使用HandlerThread类也可以。(这句话的意思是ui线程是主线程,把一些耗时的操作放入其他线程做,主线程仅仅更新视图)
4、记住消息队列的先进先出原则。
需要注意的:
一. Handler与Thread的区别。
Handler与调用者处于同一线程,如果Handler里面做耗时的动作,调用者线程会阻塞。Android UI操作不是线程安全的,并且这些操作必须在UI线程中执行。Android提供了几种基本的可以在其他线程中处理UI操作的方案,包括Activity的runOnUiThread(Runnable),View的post以及1.5版本的工具类AsyncTask等方案都采用了Handler,Handler的post对线程的处理也不是真正start一个新的线程,而是直接调用了线程的run方法,这正是google煞费苦心搞一套Handler的用意。
二.Handler对于Message的处理不是并发的。
一个Looper只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的。但是如果用不同的Looper则能达到并发的目的。Service中,onStart的执行也是阻塞的。如果一个startService在onStart执行完成之前,再次条用startService也会阻塞。如果希望能尽快的执行onStart则可以在onStart中使用handler,因为Message的send是非阻塞的。如果要是不同消息的处理也是并发的,则可以用不同的Looper实例化Handler。
三. 资源回收
向Handler对象发送类似new Message ()形式的空Message可以达到清空Message的目的,这种做法与getLooper().quit()的做法是一样的。如果利用的资源较多,应及时清理。
Android中实现view的更新有第二种方法:
Android中实现view的更新有两组方法,一组是invalidate,另一组是postInvalidate,其中前者是在UI线程自身中使用,而后者在非UI线程中使用。
Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。
Android程序中可以使用的界面刷新方法有两种,分别是利用Handler和利用postInvalidate()来实现在线程中刷新界面。
1,利用invalidate()刷新界面
实例化一个Handler对象,并重写handleMessage方法调用invalidate()实现界面刷新;而在线程中通过sendMessage发送界面更新消息。
2,使用postInvalidate()刷新界面
使用postInvalidate则比较简单,不需要handler,直接在线程中调用postInvalidate即可。
程序如下: /**
* 1 利用invalidate()刷新界面
* 实例化一个Handler对象,并重写handleMessage方法.
* 调用invalidate()实现界面刷新;
* 而在线程中通过sendMessage发送界面更新消息。
*
*/
// 在onCreate()中开启线程
new Thread(new GameThread()).start();
// 实例化一个handler
Handler myHandler = new Handler() {
// 接收到消息后处理
public void handleMessage(Message msg) {
switch (msg.what) {
case Activity01.REFRESH: mGameView.invalidate(); // 刷新界面
break;
}
super.handleMessage(msg);
}
};
}
class GameThread implements Runnable {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
Message message = new Message();
message.what = Activity01.REFRESH;
// 发送消息
Activity01.this.myHandler.sendMessage(message);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
//2,使用postInvalidate()刷新界面
// 使用postInvalidate则比较简单,不需要handler,直接在线程中调用postInvalidate即可。
class GameThread2 implements Runnable {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 使用postInvalidate可以直接在线程中更新界面
mGameView.postInvalidate();
}
}
}