当应用程序启动时,Android首先会开启一个主线程(也就是UI线程) ,主线程管理界面中的UI控件,进行事件分发。如果此时需要一个耗时的操作,例如:联网读取数据,或者读取本地较大的一个文件的时候,如果你放在主线程中的话,界面会出现假死现象。如果5秒钟还没有完成的话,会收到Android系统的一个错误提示“强制关闭”。
所以我们需要把这些耗时的操作,放在一个子线程中。这个时候,Handler就出现了。由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接受子线程传过来的数据(子线程用sendMessage()方法传递Message对象,把这些消息放入主线程队列中,配合主线程进行更新UI)。
(1)Handler一些特点
handler可以分发Message对象和Runnable对象到主线程中,每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),它有两个作用:A,安排消息或Runnable (消息和Runnable可能同时用到)在某个主线程中某个地方执行;B,安排一个动作在不同的线程中执行。
Handler中分发消息的一些方法:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable long);sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message,long)、sendMessageDelayed(Message,long)。以上post类方法允许你排列一个Runnable对象到主线程队列,SendMessage类方法允许你安排一个带数据的Message对象到队列中,等待更新。
(2)子类需要继承Hendler类,并重写handleMessage(Message msg) 方法,用于接受线程数据。实例,通过线程定时修改界面Button的名称。
package com.example.helloworld;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Button;
import android.os.Handler; //必须
import android.os.Message; //必须
import android.util.Log;
public class MainActivity extends Activity {
private final String TAG = "ThreadTest";
Button button;
MyHandler myHandler;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button)findViewById(R.id.test);
myHandler = new MyHandler();
Thread myThread = new Thread(new MyThread());
myThread.start();
}
class MyHandler extends Handler{ //主线程自己的handler
public void handleMessage(Message msg){ //重写自己的handleMessage函数
super.handleMessage(msg);
Bundle b = msg.getData(); //通过Bundle结构传数据
String color = b.getString("color"); //获得key对应的值
MainActivity.this.button.append(color); //将字符串添加至BUTTON名的末尾
}
}
class MyThread implements Runnable{
public void run(){
Message msg = new Message(); //新建msg
Bundle b = new Bundle(); //新建Bundle
b.putString("color","我的"); //将值赋给Bundle中特定的key
msg.setData(b);
try{
Thread.sleep(5000);
}catch(InterruptedException e){
e.printStackTrace();
}
Log.i(TAG,"run once ");
MainActivity.this.myHandler.sendMessage(msg); //发送消息给主线程
}
}
}
需要注意的是:android.widget.Button是android.widget.TextView的子类,所以可使用append。
(3)以上是用的线程sleep来完成定时的功能,另一种方法可以用postDelayed来实现同样的功能,对应的线程使用可以改个形式。使用方法:
A,首先创建一个Handler对象,Handler handler=new Handler();
B,然后创建一个Runnable对象,
Runnable runnable=new Runnable(){
public void run() {
// TODO Auto-generated method stub
//要做的事情,这里可以再次调用此Runnable对象,在线程中设定2秒后再执行自己,从而实现每两秒实现一次的定时器操作
handler.postDelayed(this, 2000);
}
};
C,如果是单独使用handler.postDelayed(runnable, 2000);方法,则是两秒后调用此Runnable对象,仅仅执行一次。
D,如果用完了想要关闭此定时器,可以handler.removeCallbacks(runnable);
(4)把实例2中的程序改成(3)方法来实现,代码如下:
public class MainActivity extends Activity {
private final String TAG = "ThreadTest";
Button button;
MyHandler myHandler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button)findViewById(R.id.test);
myHandler = new MyHandler();
myHandler.postDelayed(r,5000); //启动线程,5秒后。改用它的延时来代替sleep
}
class MyHandler extends Handler{
public void handleMessage(Message msg){
super.handleMessage(msg);
Bundle b = msg.getData();
String color = b.getString("color");
button.append(color);
}
}
Runnable r = new Runnable(){
public void run(){
Message msg = new Message();
Bundle b = new Bundle();
b.putString("color","我的");
msg.setData(b);
Log.i(TAG,"run once ");
myHandler.sendMessage(msg); //发消息给主线程
myHandler.postDelayed(r,5000); //有这句该程序就是个5秒的循环,没有这句就启动5秒后运行一次线程就结束
//myHandler.removeCallbacks(r); //运行到一定阶段可以关闭定时器。r用完后才会remove
}
}; //注意整个是赋值语句,并不是函数,所以有分号
}
参考原文:http://www.pin5i.com/showtopic-android-handler.html
参考原文:http://blog.csdn.net/a734797702/article/details/7634267