Handler的定义:
主要接受子线程发送的数据,并用此数据配合主线程更新UI。
解释:当应用程序第一次启动时,Android首先会开启一个主线程(Main Thread),主要负责处理与UI相关的事件,如用户的按键事件、用户接触屏幕的事件及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所有主线程通常又被叫做UI线程。
Android的消息传递机制是另一种形式的”事件处理”,这种机制主要是为了解决Android应用的多线程问题--Android平台只允许UI线程修改Activity里的UI组件,这样就会导致新启动的线程无法动态改变界面组件的属性值。但在实际Android应用开发中,尤其是涉及动画的游戏开发中,需要让新启动的线程周期性地改变界面组件的属性值,有三种方式可以实现。使用异步任务AsyncTask、AsyncTaskLoader,Service加BroadCast后台加载或者Handler来实现。
Handler类的两个作用:
1.MainThread向WorkerThread发送消息,让WorkerThread进行后台数据操作
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
public class HandlerActivity extends Activity {
//主线程向WorkerThread发送消息
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
new MyThread().start(); //开启WorkerThread
}
//简述Message MessageQueue Handler Loop 之间的关系
//主线程向WorkerThread发送消息:
//在WorkerThread中一开始需要添加Loop.prepare() 结束需要使用Loop.looper()
//主线程中:WorkerThread向MainThread发送消息:
//系统已经初始化了一个Looper对象,因此程序直接创建Handler即可,然后就通过Handler来发送消息、处理消息
class MyThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
Looper.prepare(); //
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
System.out.println(msg.arg1);
}
};
Looper.loop(); // 只有在调用了Looper的prepare()方法和loop()方法之后才会去调用handleMessage(Message msg)方法
}
}
public void onBtnClick(View v) {
Message message = handler.obtainMessage(); //创建消息对象
message.arg1 = 1; //设置消息的值
handler.sendMessage(message); //发送消息
}
}
2.WorkerThread向MainThread发送消息使主线程能够实时更新UI
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.view.View;
import android.widget.TextView;
public class Handler1Activity extends Activity {
private TextView tv;
private int count = 10;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler1);
tv = (TextView) findViewById(R.id.tv);
handler = new Handler();
}
public void onBtnClick(View v) {
new MyThread().start();
}
class CountThread implements Runnable {
@Override
public void run() {
tv.setText(count + "");
// Handler将一个WorkThread强制转换成了一个MainThread
System.out.println(Thread.currentThread().getName() + "count===>"
+ count);// .....主线程中更新UI
}
}
class MyThread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 10 && count != 0; i++) {
try {
Thread.sleep(1000);
Message message = Message
.obtain(handler, new CountThread());
// handler.sendMessage(message);//每个1s执行一次CountThread,该线程在主线程中执行
handler.sendMessageDelayed(message, 5 * 1000);
// SystemClock.uptimeMillis() 当前系统毫秒数 +5*1000相当于延时五秒
// handler.sendMessageAtTime(message,
// SystemClock.uptimeMillis()+5*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
}
}
}
}
Handler中分发消息的一些方法:
1.强制推送一个WorkerThread对象到主线程队列中,用于更新UI。
post(Runnable ) //即时发送
postAtTime(Runnable,long) //给定一个时间毫秒数。一般为当前系统时间毫秒数(SystemClock.uptimeMillis())加上一个偏移毫秒数.相当于延迟发送
postDelayed(Runnable,long) //延迟发送,给定一个时间毫秒数。为当前系统时间向后偏移的偏移量。
2.允许安排一个带数据的Message对象到主线程队列中。
sendEmptyMessage(int) //发送一个空的消息
sendMessage(Message) //即时发送消息
sendMessageAtTime(Message,long) // //给定一个时间毫秒数。一般为当前系统时间毫秒数(SystemClock.uptimeMillis())加上一个偏移毫秒数.相当于延迟发送消息
sendMessageDelayed(Message,long) 延迟发送消息,给定一个时间毫秒数。为当前系统时间向后偏移的偏移量。
Message的实例化方法:
//使用Handler实现类调用obtainMessage()方法来实例化Message。
Message msg = mHandler.obtainMessage();
//接收一个Handler实现类的对象,和一个用于更新UI的WorkerThread
Message message =Message.obtain(handler, new
例如:
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.view.View;
import android.widget.TextView;
public class Handler1Activity extends Activity {
private TextView tv;
private int count = 10;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler1);
tv = (TextView) findViewById(R.id.tv);
handler = new Handler();
}
public void onBtnClick(View v) {
new MyThread().start();
}
class CountThread implements Runnable {
@Override
public void run() {
tv.setText(count + "");
// Handler将一个WorkThread强制转换成了一个MainThread
System.out.println(Thread.currentThread().getName() + "count===>"
+ count);// .....主线程中更新UI
}
}
class MyThread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 10 && count != 0; i++) {
try {
Thread.sleep(1000);
Message message = Message
.obtain(handler, new CountThread());
// handler.sendMessage(message);//每个1s执行一次CountThread,该线程在主线程中执行
handler.sendMessageDelayed(message, 5 * 1000);
// SystemClock.uptimeMillis() 当前系统毫秒数 +5*1000相当于延时五秒
// handler.sendMessageAtTime(message,
// SystemClock.uptimeMillis()+5*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
}
}
}
}
Handler处理消息的方法:
final boolean hasMessages(int what):检查消息队列中是否包含what属性为指定值的消息。
final boolean hasMessages(int what,Object object):检查消息队列中是否包含what属性为指定值且Object属性为指定对象的消息。
void handleMessage(Message msg) :处理消息的方法。需要子类进行重写。
,更好的了解Handler的机制,我们应该首先,将Android系统整个运行进程都要烂熟于心,下面是android 进程运行图:
从图中我们可以看到,当我们从外部调用组件的时候,Service 和 ContentProvider 是从线程池那里获取线程,而Activity 和BroadcastReceiver是直接在主线程运行
因为,我们当我们的主线程队列,如果处理一个消息超过5秒,android 就会抛出一个 ANP(无响应)的消息,所以,我们需要把一些要处理比较长的消息,放在一个单独线程里面处理,把处理以后的结果,返回给主线程运行,就需要用的Handler来进行线程建的通信,关系如下图;