Handler是Android多线程技术中的一种,Handler机制有点像Win32中的消息队列的机制。
涉及Message、Handler、Looper、Message Queue等概念,下面先简单说下这几个概念
Message:数据的携带者,里面可以带有ID,就是一个封装有数据的载体,在消息队列中传输,最终由Handler处理。
Handler:消息的处理者,负责往消息队列中发送和处理来自消息队列的消息。
Message Queue:消息队列,所有由Handler发出的消息都会在这里排队处理。
Looper:一个Message Queue对应一个Looper,它的作用就是从Message Queue中取出消息执行。
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.
上面是文档中关于handler的一小段描述。
说了这么多,目前我用到Handler的话,就是开多一个线程进行一些下载图片之类的操作,然后在下载完成后,我需要通知我的主线程来更新UI,Handler就可以帮我做到这个啦。
下面就用一个小demo说下Handler和Thread的组合用法(比较正常的组合)
布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<Button
android:id="@+id/btn"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="Button"
/>
</LinearLayout>
一个textView和一个Button
Activity
public class MainActivity extends Activity {
TextView textView;
Button button;
MyHandler myHandler = new MyHandler();
MyThread myThread = new MyThread();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.textView);
button = (Button)findViewById(R.id.btn);
button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new Thread(myThread).start();
Log.e("Main Thread ID","ID "+Thread.currentThread().getId());
}
});
}
class MyHandler extends Handler {
public MyHandler(){
super();
}
public MyHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//在这里处理接受到的通知
super.handleMessage(msg);
Bundle bundle = msg.getData();
String text = bundle.getString("demo");
textView.setText(text);
}
}
class MyThread implements Runnable {
private int i=1;
@Override
public void run() {
// TODO Auto-generated method stub
while(i<10) {
Log.e("Thread ID","ID " + Thread.currentThread().getId());
try{
Thread.sleep(1000);
}
catch(InterruptedException e) {
e.printStackTrace();
}
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putString("demo", "线程第 "+i+"次运行");
i++;
msg.setData(bundle);
myHandler.sendMessage(msg); //使用sendMessage发送通知,让handler更新textView
}
i=1; //一次完成之后,进行第二次的时候 可以进入循环
}
}
}
从上面的代码可以看出,当按下button的时候,会新建一条线程,在线程中每隔1秒就让handler发送一条信息,让TextView更新文本。
在自己的Handler中需要重写handleMessage方法,在里面提取Message中的数据作相应的操作,这里要在强调一次的就是Handler的handleMessage方法是在主线程执行的,所以可以更新UI。
然后连续按下几次按钮,那么会看到的就是每次i从1到9之后,就会从头开始再进行一次,这也验证了Message Queue是FIFO的。