Handler机制原理推荐看这篇博客:http://blog.csdn.net/jiayi_yao/article/details/51082073
实例,请看本文。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cctvjiatao.handlerdemo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="21" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SendMsgAct"></activity>
<activity android:name=".PostDelayedAct"></activity>
<activity android:name=".SendMsgProgressbarAct"></activity>
<activity android:name=".IsSameThreadAct"></activity>
<activity android:name=".SendMsgLooperAct"></activity>
</application>
</manifest>
MainActivity.java
package com.cctvjiatao.handlerdemo;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
/**
* Handler机制原理详见:http://blog.csdn.net/jiayi_yao/article/details/51082073
*/
public class MainActivity extends Activity {
private final String TAG = getClass().getSimpleName();
private Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
Button btn1 = (Button) findViewById(R.id.btn1);
Button btn2 = (Button) findViewById(R.id.btn2);
Button btn3 = (Button) findViewById(R.id.btn3);
Button btn4 = (Button) findViewById(R.id.btn4);
Button btn5 = (Button) findViewById(R.id.btn5);
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(context, SendMsgAct.class));
}
});
btn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(context, PostDelayedAct.class));
}
});
btn3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(context, SendMsgProgressbarAct.class));
}
});
btn4.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(context, IsSameThreadAct.class));
}
});
btn5.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(context, SendMsgLooperAct.class));
}
});
}
}
activity_main.xml
<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"
tools:context="com.cctvjiatao.handlerdemo.MainActivity" >
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="sendMsg" />
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PostDelayedAct" />
<Button
android:id="@+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SendMsgProgressbarAct" />
<Button
android:id="@+id/btn4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="IsSameThreadAct" />
<Button
android:id="@+id/btn5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SendMsgLooperAct" />
</LinearLayout>
SendMsgAct.java
package com.cctvjiatao.handlerdemo;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Button;
/**
* @作者: jiatao
* @修改时间:2016-4-10 下午10:55:26
* @包名:com.cctvjiatao.handlerdemo
* @文件名:SendMsgAct.java
* @版权声明:www.cctvjiatao.com
* @功能: 不断变化的按钮
*/
public class SendMsgAct extends Activity {
private final String TAG = getClass().getSimpleName();
private MyHandler mMyHandler;
private Button btn_variable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_sendmsg);
btn_variable = (Button) findViewById(R.id.btn_variable);
mMyHandler = new MyHandler();
MyThread m = new MyThread();
new Thread(m).start();
}
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e(TAG, "handleMessage...");
Bundle b = msg.getData();
String btnStr = b.getString("name");
btn_variable.append(btnStr);
}
}
class MyThread implements Runnable {
@Override
public void run() {
while (true) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg = new Message();
Bundle b = new Bundle();
b.putString("name", "Monkey");
msg.setData(b);
SendMsgAct.this.mMyHandler.sendMessage(msg);
Log.e(TAG, "sendMessage...");
}
}
}
}
PostDelayedAct.java
package com.cctvjiatao.handlerdemo;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
/**
* @作者: jiatao
* @修改时间:2016-4-10 下午11:55:26
* @包名:com.cctvjiatao.handlerdemo
* @文件名:PostDelayedAct.java
* @版权声明:www.cctvjiatao.com
* @功能: Handler.postDelayed + Runnable
* 这个例子是最简单的介绍handler的使用:是将handler绑定到它所建立的线程中.
*/
public class PostDelayedAct extends Activity {
private final String TAG = getClass().getSimpleName();
private TextView tv_msg;
private Button btn_start, btn_end;
Handler handler = new Handler();
Runnable rb = new Runnable(){
public void run() {
//线程每次执行时输出"UpdateThread..."文字,且自动换行
tv_msg.append("\nUpdateThread...");
//延时3s后又将线程加入到线程队列中
handler.postDelayed(rb, 3000);//可以尝试注释本行代码,观察变化
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_postdelayed);
initView();
}
private void initView() {
tv_msg = (TextView) findViewById(R.id.tv_msg);
btn_start = (Button) findViewById(R.id.btn_start);
btn_end = (Button) findViewById(R.id.btn_end);
btn_start.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//将线程接口立刻送到线程队列中
handler.post(rb);
Log.e(TAG, "start...");
}
});
btn_end.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//将线程接口从线程队列中移除
handler.removeCallbacks(rb);
Log.e(TAG, "end...");
}
});
}
}
SendMsgProgressbarAct.java
package com.cctvjiatao.handlerdemo;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* @作者: jiatao
* @修改时间:2016-4-10 下午11:55:26
* @包名:com.cctvjiatao.handlerdemo
* @文件名:SendMsgProgressbarAct.java
* @版权声明:www.cctvjiatao.com
* @功能: 例子中用到了handler的消息队列机制,
* 即通过handler中一个线程向消息队列中用sendMessage方法发送消息,发送的消息当然可以用来传递参数。
* 在handler中用handleMessage来处理消息,处理方法是获得消息队列中的消息参数,用这些参数来完成另外一些功能。
*/
public class SendMsgProgressbarAct extends Activity {
private final String TAG = getClass().getSimpleName();
private ProgressBar pb_handler;
private Button btn_start;
//创建一个handler,内部完成处理消息方法
Handler handler = new Handler(){
public void handleMessage(Message msg) {
Log.e(TAG, "sendMessage...");
//显示进度条
pb_handler.setProgress(msg.arg1);
//重新把进程加入到进程队列中
handler.post(rb);//注释本行代码,观察变化
};
};
Runnable rb = new Runnable(){
int i = 0;
public void run() {
i += 10;
//首先获得一个消息结构
Message msg = handler.obtainMessage();
//给消息结构的arg1参数赋值
msg.arg1 = i;
//延时1s,java中的try+catch用来排错处理
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//把消息发送到消息队列中
handler.sendMessage(msg);
Log.e(TAG, "sendMessage...");
if(i == 100){
//把线程从线程队列中移除
handler.removeCallbacks(rb);
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_progressbar);
initView();
}
private void initView() {
pb_handler = (ProgressBar) findViewById(R.id.pb_handler);
btn_start = (Button) findViewById(R.id.btn_start);
btn_start.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
pb_handler.setVisibility(View.VISIBLE);
//将线程接口立刻送到线程队列中
handler.post(rb);
Log.e(TAG, "start...");
}
});
}
}
IsSameThreadAct.java
package com.cctvjiatao.handlerdemo;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
/**
* @作者: jiatao
* @修改时间:2016-4-10 下午11:55:26
* @包名:com.cctvjiatao.handlerdemo
* @文件名:IsSameThreadAct.java
* @版权声明:www.cctvjiatao.com
* @功能: 验证仅使用handler的post方法是否处于同一个线程
* 例子PostDelayedAct和例子SendMsgProgressbarAct表面上看handler使用了post方法启动了runnbale,
* 其实启动的线程和activity主线程是同一个线程,因为它只是运行了线程的run方法,而不是start方法。
*/
public class IsSameThreadAct extends Activity {
private final String TAG = getClass().getSimpleName();
//新建一个handler
Handler handler = new Handler();
Runnable rb = new Runnable(){
public void run() {
//打印新建线程信息
Log.e(TAG, "handler_id---->"+Thread.currentThread().getId());
Log.e(TAG, "handler_name---->"+Thread.currentThread().getName());
//延时10s,为了观察主界面中内容出现的时间
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//将runnable加载到handler的线程队列中去
handler.post(rb);
/*Thread t = new Thread(rb);
t.start();*/
setContentView(R.layout.act_postdelayed);
//打印activtiy线程信息
Log.e(TAG, "activity_id---->"+Thread.currentThread().getId());
Log.e(TAG, "activity_name---->"+Thread.currentThread().getName());
}
}
/**
* 结果说明这两个线程确实是同一线程,并且可以看出主界面中的文字大概过了10s才显示出来,
* 因为语句setContentView(R.layout.activity_main);放在了handler的post启动语句后面,
* 而handler绑定的线程中又延时了10s,所以同时也证明了只有是同一个线程才会出现这种情况。
*/
/**
* 如果把语句:
* handler.post(rb);
* 换成:
* Thread t = new Thread(rb);
* t.start();
* 其它的不变,则程序运行时主界面内容立刻就显示出来了,且打印日志为。。。
* 这两者都说明这样绑定的线程与它所在的activity线程就不是同一个线程了。
*/
SendMsgLooperAct.java
package com.cctvjiatao.handlerdemo;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* @作者: jiatao
* @修改时间:2016-4-10 下午11:55:26
* @包名:com.cctvjiatao.handlerdemo
* @文件名:SendMsgLooperAct.java
* @版权声明:www.cctvjiatao.com
* @功能: 学会使用怎样在新线程中处理消息的方法
* 1)这个例子将学会怎样不使用runnable来启动一个线程,而是用HandlerThread的looper来构造一个handler,
* 然后该handler自己获得消息,并传递数据,然后又自己处理消息,当然这是在另一个线程中完成的。
* 2)消息结构中传递简单的整型可以采用它的参数arg1和arg2,或者传递一些小的其它数据,
* 可以用它的object,该object可以是任意的对象。
* 当需要传送比较大的数据是,可以使用消息的setData方法,该方法需要传递一个Bundle的参数。
* Bundle中存放的是键值对的map,只是它的键值类型和数据类型比较固定而已。
*/
public class SendMsgLooperAct extends Activity {
private final String TAG = getClass().getSimpleName();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_postdelayed);
Log.e(TAG, "activity_ID---->" + Thread.currentThread().getId());
Log.e(TAG, "activity_Name---->" + Thread.currentThread().getName());
// 新建一个HanderThread对象,该对象实现了用Looper来处理消息队列的功能
HandlerThread handler_thread = new HandlerThread("handler_thread");
handler_thread.start();
// MyHandler类是自己继承的一个类,这里采用hand_thread的Looper来初始化它
MyHandler my_handler = new MyHandler(handler_thread.getLooper());
// 获得一个消息msg
Message msg = my_handler.obtainMessage();
// 采用Bundle保存数据,Bundle中存放的是键值对的map,只是它的键值类型和数据类型比较固定而已
Bundle b = new Bundle();
b.putString("whether", "晴天");
b.putInt("temperature", 34);
msg.setData(b);
// 将msg发送到自己的handler中,这里指的是my_handler,调用该handler的HandleMessage方法来处理该mug
msg.sendToTarget();
}
class MyHandler extends Handler {
// 空的构造函数
public MyHandler() {
}
// 以Looper类型参数传递的函数,Looper为消息泵,不断循环的从消息队列中得到消息并处理,
// 因此,每个消息队列都有一个Looper,因为Looper是已经封装好了的消息队列和消息循环的类
public MyHandler(Looper looper) {
// 调用父类的构造函数
super(looper);
}
@Override
public void handleMessage(Message msg) {
Log.e(TAG, "Handler_ID---->" + Thread.currentThread().getId());
Log.e(TAG, "Handler_Name---->" + Thread.currentThread().getName());
// 将消息中的bundle数据取出来
Bundle b = msg.getData();
String whether = b.getString("whether");
int temperature = b.getInt("temperature");
Log.e(TAG, "Handler_ID---->" + "whether= " + whether + " ,temperature= " + temperature);
}
}
}
act_sendmsg.xml
<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"
tools:context="com.cctvjiatao.handlerdemo.SendMsgAct" >
<Button
android:id="@+id/btn_variable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="多变的按钮" />
</LinearLayout>
act_postdelayed.xml
<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" >
<TextView
android:id="@+id/tv_msg"
android:layout_width="fill_parent"
android:layout_height="400dip"
android:text="@string/hello_world"/>
<Button
android:id="@+id/btn_start"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="开始" />
<Button
android:id="@+id/btn_end"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="结束" />
</LinearLayout>
act_progressbar.xml
<RelativeLayout 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" >
<Button
android:id="@+id/btn_start"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="开始" />
<ProgressBar
android:id="@+id/pb_handler"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="100dip"
android:layout_alignParentTop="true"
android:visibility="gone" />
</RelativeLayout>