参考自:
http://blog.csdn.net/itachi85/article/details/8035333
http://blog.csdn.net/wyp880303/article/details/6285193
http://www.cnblogs.com/dawei/archive/2011/04/09/2010259.html
以下为自己对handler的理解,可能会有错误的理解,请指正
1.线程+handler+looper内涵
线程:同时处理不同的业务
handler:用来满足线程间的通信
looper:用来管理特定线程内的对象之间的消息交换(处理消息队列)
2.1.线程+handler+looper关系
1)Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。
2)Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
3) Message Queue(消息队列):用来存放线程放入的消息。
4)一个Looper可以对应多个handler
5)handler.post()执行runnable里的代码,handler.post不需要放在Runnable中,handler.sendMessage();一定要放在线程run()方法中,否则会有问题
6)Hander handler = new Handler(Loop)在哪个线程里创建就会匹配到哪个线程的Looper
注意:一个handler可处理多个线程,一个线程只有一个Looper,handler有两种使用方法
1)handler.post(new Runnable());把线程push到消息队列里,为什么要把线程push到消息队列里?(handler.post(runnable) 与thread.start()功能一样,运行该句后会运行run()里面动作)
2)handler.sendMessage();类似ajax处理返回的数据,Looper会从消息队列里取出消息,发送给handler处理?
答:子线程通过handler才能创建消息,子线程通过handler才能把消息发送给主线程消息队列,Looper会循环查询消息队列,要是有消息了,主线程会调用handler处理消息
3.Handler处理消息
UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。
子线程通过Handler、Looper与UI主线程通信的流程如图所示。(类似ajax返回)
附加说明:
<span style="font-size:10px;">ProgressDialog.show(this, prompt_state, prompt_tip);
</span>
<span style="font-size:10px;">new Thread(new Runnable)(){
@Override
public void run() {
promptMsg = "很抱歉获取不到您的位置,请寻找GPS信号良好的地方,重新尝试";
Looper.prepare();
creatMsgDialog(title, promptMsg);
Looper.loop();
}
}).start();</span>
第一段代码是在UI主线程中,所以可以实现对UI的更新,第二段代码创建了一个子线程,此时无法直接更新UI,需要通过Looper来更新,looper循环查询UI主线程消息队列,要是有消息,looper会把消息发送给handler处理。注意:这里looper为UI主线程的Looper。当然也可以handler.sendMessage()在重写的handleMessage()方法里更新UI,
一、UI更新只能是UI主线程实现,Handler 主要接受子线程发送的数据, 并用此数据配合主线程更新UI
解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发, 比如说, 你要是点击一个 Button, Android会分发事件到Button上,来响应你的操作。 如果此时需要一个耗时的操作,例如: 联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 "强制关闭". 这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,Android主线程是线程不安全的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的. 这个时候,Handler就出现了来解决这个复杂的问题,由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据) , 把这些消息放入主线程队列中,配合主线程进行更新UI。
二、Handler一些特点
handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),
它有两个作用: (1): 安排消息或Runnable 在某个主线程中某个地方执行, (2)安排一个动作在不同的线程中执行
Handler中分发消息的一些方法
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
以上post类方法允许你排列一个Runnable对象到主线程队列中,
sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新.
三、实例
(1) 子类需要继承Handler类,并重写handleMessage(Message msg) 方法, 用于接受线程数据
以下为一个实例,它实现的功能为 : 通过线程修改界面Button的内容
package com.yangyu.myactionbar;
import android.app.ActionBar;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
public class MainActivity extends Activity {
Button button;
MyHandler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
// TODO Auto-generated method stub
button = (Button) findViewById(R.id.btn);
/*
* 当创建一个新的Handler实例时, 它会绑定到当前线程和消息的队列中,开始分发数据
* Handler有两个作用
* 1)定时执行Message和Runnalbe 对象
* 2) 让一个动作,在不同的线程中执行.
*
* Handler它安排消息,用以下方法
* post(Runnable)
* postAtTime(Runnable,long)
* postDelayed(Runnable, long)
* sendEmptyMessage(int)
* sendMessage(Message)
* sendMessageAtTime(Message, long)
* sendMessageDelayed(Message, long)
*
* 以上方法以post开头的处理Runnable对象
* sendMessage()处理Message,Message里可包含数据
* */
handler = new MyHandler();
MyRunnable runnable = new MyRunnable();
new Thread(runnable).start();
}
class MyHandler extends Handler{
public MyHandler(){
}
public MyHandler(Looper looper){
super(looper);
}
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
//此处更新UI
Bundle b = msg.getData();
String color = b.getString("color");
button.append(color);
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Message msg = handler.obtainMessage();
Bundle b = new Bundle();
b.putString("color", "我的");
msg.setData(b);
handler.sendMessage(msg);//向handler发送消息,更新ui
}
}
}
匿名方式写法
package com.yangyu.myactionbar;
import android.app.ActionBar;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
public class MainActivity extends Activity {
Button button;
MyHandler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
// TODO Auto-generated method stub
button = (Button) findViewById(R.id.btn);
/*
* 当创建一个新的Handler实例时, 它会绑定到当前线程和消息的队列中,开始分发数据
* Handler有两个作用
* 1)定时执行Message和Runnalbe 对象
* 2) 让一个动作,在不同的线程中执行.
*
* Handler它安排消息,用以下方法
* post(Runnable)
* postAtTime(Runnable,long)
* postDelayed(Runnable, long)
* sendEmptyMessage(int)
* sendMessage(Message)
* sendMessageAtTime(Message, long)
* sendMessageDelayed(Message, long)
*
* 以上方法以post开头的处理Runnable对象
* sendMessage()处理Message,Message里可包含数据
* */
handler = new MyHandler();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(10000);
Message msg = handler.obtainMessage();
String color = "我的";
msg.what = 1;
msg.obj = color;
handler.sendMessage(msg);//向handler发送消息,更新ui
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
class MyHandler extends Handler{
public MyHandler(){
}
public MyHandler(Looper looper){
super(looper);
}
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
//此处更新UI
if(msg.what == 1){
try{
String color =(String)msg.obj;
button.append(color);
}catch(Exception e){
e.printStackTrace();
}
}
}
}
}
(2)handler.post,handler.post(Runnable)才会开始运行线程,例子为按开始button,每3s打印一次“更新线程”,按结束button结束打印(结束线程)。
//注意:执行postDelayed方法,由于里面设置的间隔时间,所以每3秒会调价一个handler对象到线程队列中
package com.yangyu.myactionbar;
import android.app.ActionBar;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
private Button mybutton1;
private Button mybutton2;
private TextView text;
private Handler handler;
private Runnable updateThread;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mybutton1 = (Button)findViewById(R.id.btn1);
mybutton2 = (Button)findViewById(R.id.btn2);
text = (TextView) findViewById(R.id.content);
//创建Handler对象
handler = new Handler();
/**
* 将要执行的操作卸载写入线程对象的run()方法当中
*/
updateThread = new Runnable()
{
public void run()
{
text.append("更新线程\n");
//当前还未执行,在run方法内部,执行postXX的方法,每隔3秒会执行一次
handler.postDelayed(updateThread, 3000);//postDelayed()使得每隔3s执行一次
}
};
mybutton1.setOnClickListener(new Button.OnClickListener()
{
@Override
public void onClick(View arg0) {
/**
* 调用Handler的post方法,将要执行的线程对象添加到
* 线程队列中
*/
handler.post(updateThread);//立即执行runnbale里面内容
}
});
mybutton2.setOnClickListener(new Button.OnClickListener()
{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//移除runnable
handler.removeCallbacks(updateThread);
}
});
}//end OnCreate
}
(3)参考 http://www.iteye.com/topic/1062942
说明:Handler.post(Runnable)会直接把线程放入UI主线程消息队列,由于消息队列是先进先出,所以handler.post(Runnbale)先执行runnable里的所有代码,runnable里的代码执行完毕,才会去执行HandlerMessage()里面的代码,如:当i=100时,handler.sendMessage(msg)把消息放进消息队列,但是要等待runnable其他代码执行完毕,因此先执行判断是否i=100,如果i=100,handler.removeCallback(runnable),执行完之后再去执行handleMessage里的代码,由于之前的消息已经在队列里了,所以不是我这里先执行了判断就不执行handleMessage里的内容了。可以DEBUG一下。具体流程为
1、当点击按钮后,会执行按钮的onClick方法中的
bar.setVisibility(View.VISIBLE);
handler.post(handlerThread);
将进度条显示出来,并且将线程对象加入到线程队列中
2、线程对象对先打印出一个“开始线程”,然后i的值增加10,然后从系统中获取一个Message对象
3、将i赋给Message对象的参数arg1
4、当前线程休眠5秒,然后通过sendMessage方法发送一个Message对象发送到消息队列中
5、然后再执行,通过handleMessage方法设置进度条的值,并且将其加入到进程队列中
Handler handler = new Handler()
{
public void handleMessage(Message msg)
{
bar.setProgress(msg.arg1);
handler.post(handlerThread);
}
};
6、循环执行,直到i=100,进度条隐藏,并将线程对象从线程队列中取出
package com.yangyu.myactionbar;
import android.app.ActionBar;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainActivity extends Activity {
private ProgressBar bar = null;
private Button start = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bar = (ProgressBar)findViewById(R.id.progress1);
start = (Button)findViewById(R.id.start);
start.setOnClickListener(new Button.OnClickListener()
{
@Override
public void onClick(View v) {
bar.setVisibility(View.VISIBLE);
handler.post(handlerThread);
}
});
}
/**
* 使用匿名内部类来复写hanlder当中的hanldrMessage方法
* 这里的msg对象就是从线程部分发送过来的对象
*/
Handler handler = new Handler()
{
public void handleMessage(Message msg)
{
bar.setProgress(msg.arg1);
handler.post(handlerThread);
}
};
//线程类,该类使用的是匿名内部类的方式进行声明
Runnable handlerThread = new Runnable()
{
int i = 0;
public void run()
{
System.out.println("开始线程");
i = i + 10;
/**
* 得到一个消息对象,Message类是由android操作系统提供
* obtainMessage方法用来得到Message对象
*/
Message msg = handler.obtainMessage();
/**
* Message中有个成员变量,即msg独享的arg1参数
* 将其值设置为i。用arg1或arg2这两个成员变量传递
* 消息,优点是系统性能消耗较少
*/
msg.arg1 = i;
try {
//当前线程休眠1秒
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/**
* 发送一个消息,用sendMessage是将msg加入到消息
* 队列中。而post是将线程加入到线程队列中
*/
handler.sendMessage(msg);
if( i == 100)
{
/**
* 如果i=100的时候,就将线程对象
* 从handler当中移除
*/
handler.removeCallbacks(handlerThread);
bar.setVisibility(View.GONE);
}
}
};
}
xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ProgressBar
android:id="@+id/progress1"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
<Button
android:id="@+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="点击我" />
</LinearLayout>