在Android系统中,当一个应用程序启动时,首先会启动一个主线程(也被称为UI线程),该线程负责管理界面中的UI控件,进行事件分发,并响应用户的操作。在主线程中不能执行比较耗时的操作(一般不能超过5s),否则Android会认为该应用无响应,便会弹出程序没有响应对话框。如果要执行一些像下载、解析大文件等比较耗时的操作的话,则可以放在Service组件中或放在子线程中执行。这时我们又遇到了一个问题,在Android中不允许在子线程中更新UI组件,UI的更新只能在主线程中执行。Android中为我们提供Handler这个类来解决以上的问题。
下面是Handler的详细用法:
1. Handler简介:
Handler在文档中的定义是:Handler主要用来接收子线程发送的数据,并用此数据配合主线程更新UI。
Handler可以分发Message对象和Runnable对象到主线程中,每个Handler实例,一旦创建后,系统就会把该实例与一个线程和该线程的消息队列绑定带一起,这将可以发送消息和runnable对象给该消息队列,并在消息队列出口处理它们。 当一个进程启动时,主线程独立执行一个消息队列,该队列管理着应用顶层的对象(如:activities、broadcast receivers等等)和所有创建的窗口。你可以创建自己的一个线程,并通过handler来与主线程进行通信。这可以通过在新的线程中调用主线程的handler的post和sendmessage操作来实现。
2. Handler的用途:
1。按照时间计划,在未来某时刻,对处理一个消息或执行某个runnable实例。
2。把一个对另外线程对象的操作请求放入消息队列中,从而避免线程间冲突。
3. Handler与线程的关系:
使用Handler的post方法将Runnable对象放到Handler的线程队列中后,该Runnable的执行其实并未单独开启线程,而是仍然在当前Activity线程中执行的,Handler只是调用Runnable对象的run方法。
默认情况下,Handler接受的是当前线程下的消息循环实例(使用Handler(Looper looper)、Handler(Looper looper, Handler.Callback callback)可以指定线程),同时一个消息队列可以被当前线程中的多个对象进行分发、处理(在UI线程中,系统已经有一个Activity来处理了,你可以再起若干个Handler来处理)。在实例化Handler的时候,Looper可以是任意线程的,只要有Handler的指针,任何线程也都可以sendMessage。Handler对于Message的处理不是并发的。一个Looper 只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的(handleMessage()方法里不应该有耗时操作,可以将耗时操作放在其他线程执行,操作完后发送Message(通过sendMessges方法),然后由handleMessage()更新UI)
消息通过如下方法使用: post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long)
methods. post之类函数可以传输一个runnable对象给消息队列,并在到达消息队列后被调用。sendmessage之类函数可以传送一个包含数据的message对象,该message对象可以被Handler类的handleMessage(Message) 方法所处理。
post之类函数和sendmessage之类的函数都可以指定消息的执行时机,是立即执行、稍后一段时间执行,还是在某个确定时刻执行。这可以用来实现超时、消息或其他时间相关的操作。
下面是一个Demo,使用Handler更新进度条:
package com.xzq;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
public class MainActivity extends Activity {
ProgressBar bar = null;
Button start = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bar = (ProgressBar) findViewById(R.id.progressBar1);
start = (Button) findViewById(R.id.button1);
start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
bar.setVisibility(View.VISIBLE);
updateBar.post(updateThread);
}
});
}
Handler updateBar = new Handler() {
@Override
public void handleMessage(Message msg) {
bar.setProgress(msg.arg1);
setTitle("" + msg.arg1);
updateBar.post(updateThread);
}
};
Runnable updateThread = new Runnable() {
int i = 0;
@Override
public void run() {
System.out.println("Runnable --> " + Thread.currentThread().getId()
+ " " + Thread.currentThread().getName());
i = i + 10;
Message msg = updateBar.obtainMessage();
msg.arg1 = i;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i > 100) {
updateBar.removeCallbacks(updateThread);
}else{
updateBar.sendMessage(msg);
}
}
};
}
布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="@string/hello" />
<ProgressBar android:id="@+id/progressBar1"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:visibility="gone" style="?android:attr/progressBarStyleHorizontal"></ProgressBar>
<Button android:text="开始" android:id="@+id/button1"
android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
</LinearLayout>
代码比较简单,不做过多介绍了。该实例中Handler是在主线程,也就是UI线程中执行的。
上面说到,Handler可以在其他线程中执行,下面是一个Handler在其他线程中执行的Demo:
public class HandlerTest2 extends Activity{
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
System.out.println("Test: " + Thread.currentThread().getId());;
//生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能,这个类由Androi框架提供。
HandlerThread handlerThread = new HandlerThread("handler_thread");
handlerThread.start();
MyHandler myHandler = new MyHandler(handler.getLooper());
Message msg = new Message();
//将msg发送到目标对象,所谓的目标对象,就是生成该msg对象的handler对象
Bundle bundler = new Bundle();
bundle.putInt("age",22);
bundle.putString("name","xuzhiqi");
msg.setData(bundle);
msg.sendToTarget();
}
class myHandler extends Handler{
public MyHandler(){}
public MyHandler(Looper looper){
super(looper);
}
public void handleMessage(Message msg){
Bundle b = msg.getData();
int age = b.getInt("age");
String name = b.getString("name");
System.out.println("age is " + age + ", name is " + name);
System.out.println("Handler -->" + Thread.currentThread().getId());
System.out.println("handlerMessage");
}
}
}