一般情况下,无论是否使用了后台线程,handler的处理实际就是UI主线程的处理,一般的使用方式为我们通过后台线程执行某些操作,如果需要进行ui互动,将消息发送到handler的队列中,然后在ui主线程中进行处理。这是我们通常用的情况。
之前我们讨论过Ui归ui,处理归处理。然而可能有这样的请求,举个例子,在某些情况下,handler收到消息触发的处理中可能会有说了sleep()这样导致main线程进入sleep()状态,不是我们期待的。因此我们希望通过一个线程专门处理handler的消息,这个线程也是依次从handler的队列中获取信息,逐个进行处理,保证按去哪,不会出现混乱引发异常。
针对此android提供了HandlerThread。方式使用方法如下:
//步骤1:创建HandlerThread的一个对象,并开启这个线程,handlerthread将通过looper来处理handler对列中的消息,也就是如果发现Handler中有消息,将在HandlerThread这个线程中进行处理。
HandlerThread ht =new HandlerThread (“handler_thread”);
//步骤2 :启动handlerthread这个线程
ht.start();
//步骤3:创建handler时,带上looper参数,即handlerThread.getLooper()。注意必须在handlerThread启动后才能调用,否则会出错,getLooper()会返回null,则程序异常出错
Handler handler=new Handler (ht.getLooper()){
…..
public void handleMessage(Message msg){
…../这里的处理,将不在主线程中执行,而在handlerthread线程中执行,可以通过Thread.currentThread().getId()或者Thread.currentThread().getName()来确定/
}
};
示例:
界面中只有一个button,点击button后会在HandlerThread中执行一个耗时操作。本程序主要观察handler的handleMessage()方法是在哪个线程中执行的。
“`
package com.example.handler03;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private Button button;
private TextView textview ;
public static final int PARAM=1;
HandlerThread ht=new HandlerThread(“handler_thread”);
/*
* 此处的Runnable对象用于判断所执行程序位于哪个线程,可调用runOnUiThread(runAction)方法判断
* 调用该方法实际上就是执行的Runnable对象的run方法
*/
Runnable runAction=new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
Log.d("当前线程","------>"+Thread.currentThread().getName());
Toast.makeText(getApplicationContext(),"执行所在线程" , Toast.LENGTH_LONG);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);
button=(Button)findViewById(R.id.buttonId);
textview=(TextView)findViewById(R.id.textViewId);
//handlerThread线程必须要在创建handler之前执行,因为创建
//handler时要用到HandlerThread对象的looper对象
ht.start();
//获取ht线程所对应的looper对象,问题是这个looper对象是怎样得到的?
final Handler handler=new Handler(ht.getLooper()){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
for(int i=0;i<=2;i++){
try {
//按照传统做法当在子线程调用sendMessage时,
//在主线程中的handleMessage会执行,但是主线程不能进行网络访问(网络不稳定),也不能进行耗时比较长的操作
//而现在的handleMessage操作是在子线程HandlerThread线程中进行的,所以不会引发ANR异常
Thread.sleep(2000);//模仿耗时操作
//一下两句话都是输出当前线程
Log.d("当前线程","------>"+Thread.currentThread().getName());
runOnUiThread(runAction);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId()){
case R.id.buttonId:
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//Looper.prepare();
Message msg=handler.obtainMessage();
handler.sendMessage(msg);
Log.d("OnClick","sendMessage WorkerThread--------->"+Thread.currentThread().getName());
//Looper.loop();
}
}).start();
break;
default:
break;
}
}
});
}
}
查看程序的日志输出
03-06 21:32:00.918: D/OnClick(28927): sendMessage WorkerThread———>Thread-22280
03-06 21:32:02.919: D/当前线程(28927): ——>handler_thread
03-06 21:32:02.919: D/当前线程(28927): ——>main
03-06 21:32:04.920: D/当前线程(28927): ——>handler_thread
03-06 21:32:04.920: D/当前线程(28927): ——>main
03-06 21:32:06.920: D/当前线程(28927): ——>handler_thread
03-06 21:32:06.920: D/当前线程(28927): ——>main
从日志输出可知与文章最初叙述相符