Android和Handler那些事
目录
1 HANDLER的简单使用 1
2 HANDLER的消息传递 4
3 HANDLER的线程异步 8
[b]1 Handler的简单使用[/b]
Handler主要用于异步消息的处理:当调用Handler发送消息方法发出一个消息之后,消息进入一个消息队列,发送消息的方法即刻返回,而Handler的消息处理方法则被调用,逐个的从消息队列中将消息取出,然后对消息进行处理,就是将消息发送和消息处理实现异步化。这种机制通常用来处理相对耗时比较长的操作。
下面通过一个简单的android应用程序来了解Handler的使用
创建一个android应用程序,activity1的实现如下:
运行界面如下:
[img]http://dl.iteye.com/upload/attachment/0083/2396/3605a299-da49-334a-a40f-244901ee092f.png[/img]
当点击start按钮时,程序每输出:
start button click!
my thread handler
每隔三秒输出一句:
my thread handler
当点击end按钮后,程序输出:
end button click!
[b]2 Handler的消息传递[/b]
上面的例子只是简单handler使用实例,并没有用到handler消息对象来实现消息的异步处理,下面我们来看看怎样利用handler来实现消息异步处理。
基于上面的例子我们可以稍作修改实现一个进度条更新功能。
实现如下:
新创建一个activity实现如下:
新创建一个activity布局文件,activity2.xml
修改AndroidManifest.xml文件
运行程序界面如下:
[img]http://dl.iteye.com/upload/attachment/0083/2398/82fe031a-55fb-3b2a-b759-d92d8de003da.png[/img]
点击ok按钮后,程序进度条每隔一秒就会更新进度,后台输出如下:
从输出结果我们可以看到,handler的这种消息传递的异步处理都是在id为1的线程中完成整个handler过程,整个过程实际上是单线程处理的,没有真正实现异步化处理,如果要实现handler消息异步化处理可以通过HandlerThread来实现。
[b]3 Handler的线程异步[/b]
基于2中的程序稍作修改可以实现Handler的线程异步处理消息功能。
新创建一个activity实现如下:
修改AndroidManifest.xml文件的程序入口为Activity3
运行程序后点击OK按钮,后台输出如下:
从输出结果可以看到activity的主线程id号为1,而消息处理线程的id号为9。整个handler过程由两个线程参与,主线程负责发生消息,而handerThread线程负责处理处理消息。
目录
1 HANDLER的简单使用 1
2 HANDLER的消息传递 4
3 HANDLER的线程异步 8
[b]1 Handler的简单使用[/b]
Handler主要用于异步消息的处理:当调用Handler发送消息方法发出一个消息之后,消息进入一个消息队列,发送消息的方法即刻返回,而Handler的消息处理方法则被调用,逐个的从消息队列中将消息取出,然后对消息进行处理,就是将消息发送和消息处理实现异步化。这种机制通常用来处理相对耗时比较长的操作。
下面通过一个简单的android应用程序来了解Handler的使用
创建一个android应用程序,activity1的实现如下:
package com.example;
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class Activity1 extends Activity {
//开始按钮
private Button start;
//结束按钮
private Button end;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity1);
//根据id获取按钮控件
start = (Button)findViewById(R.id.start);
end = (Button)findViewById(R.id.end);
//给按钮设置事件监听器
start.setOnClickListener(startClick);
end.setOnClickListener(endClick);
}
//点击开始按钮的事件监听器
OnClickListener startClick = new OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("start button click!");
/**
* 调用handler的post()方法将线程处理对象放到线程队列中去.
* 线程队列中的线程处理对象会被取出执行
*/
myHandler.post(myThreadHandler);
}
};
//结束按钮的事件监听器
OnClickListener endClick = new OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("end button click!");
/**
* removeCallbacks()方法与post()方法想反,
* 调用该方法可以将线程队列中的线程处理对象移出队列
*/
myHandler.removeCallbacks(myThreadHandler);
}
};
//handler对象
Handler myHandler = new Handler(){};
//线程处理对象
Runnable myThreadHandler = new Runnable() {
@Override
public void run() {
System.out.println("my thread handler");
/**
* 调用postDelayed()方法可以定时向线程队列中添加线程处理对象。
* 第一个参数是Runnable类型:将要执行的线程处理对象
* 第二个参数是long类型:延迟的时间,以毫秒为单位
* 即每隔3秒后向线程队列中添加一个线程处理对象
*/
myHandler.postDelayed(myThreadHandler, 3000);
}
};
//按键事件
public boolean onKeyUp(int keyCode, KeyEvent event) {
//当按键为回退键是接受这个activity
if (keyCode == KeyEvent.KEYCODE_BACK) {
Activity1.this.finish();
}
return true;
};
}
运行界面如下:
[img]http://dl.iteye.com/upload/attachment/0083/2396/3605a299-da49-334a-a40f-244901ee092f.png[/img]
当点击start按钮时,程序每输出:
start button click!
my thread handler
每隔三秒输出一句:
my thread handler
当点击end按钮后,程序输出:
end button click!
[b]2 Handler的消息传递[/b]
上面的例子只是简单handler使用实例,并没有用到handler消息对象来实现消息的异步处理,下面我们来看看怎样利用handler来实现消息异步处理。
基于上面的例子我们可以稍作修改实现一个进度条更新功能。
实现如下:
新创建一个activity实现如下:
package com.example;
import com.example.test_exp_14.R;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
public class Activity2 extends Activity {
//开始按钮
private Button btn;
//进度条
private ProgressBar bar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity2);
//根据id获取控件对象
bar = (ProgressBar)findViewById(R.id.bar);
btn = (Button)findViewById(R.id.btn);
//给开始按钮设置事件监听器
btn.setOnClickListener(btnClick);
}
//开始按钮事件监听器
OnClickListener btnClick = new OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("main thread id:"+Thread.currentThread().getId());
//将进度条设置为可见
bar.setVisibility(View.VISIBLE);
//调用handler的post方法将更新线程对象添加到线程队列中进行处理
updateBarHandler.post(updateThreadHandler);
}
};
//handler对象
Handler updateBarHandler = new Handler(){
/**
* 当消息队列中传入消息时会触发该方法
*/
public void handleMessage(Message msg) {
//根据msg消息对象来设置进度条当前的进度
bar.setProgress(msg.arg1);
/**
* 判断进度条当前进度是否达到最大值
* 如果没有达到最大值,则将修改进度条线程对象添加到线程队列中
* 如果达到最大值,则将修改进度条线程对象从线程队列中移出
*/
if(msg.arg1 < bar.getMax()){
updateBarHandler.post(updateThreadHandler);
}else{
System.out.println("thread id:"+Thread.currentThread().getId()+" process bar end");
updateBarHandler.removeCallbacks(updateThreadHandler);
}
};
};
//修改进度条线程对象
Runnable updateThreadHandler = new Runnable() {
int i = 0; //进度条初始值
int step = 10; //进度条步长
@Override
public void run() {
//进度条增加步长
i = i+step;
System.out.println("thread id:"+Thread.currentThread().getId()+" process bar "+i);
//获取handler的消息对象
Message msg = updateBarHandler.obtainMessage();
//将当前进度赋值给msg对象中成员变量保存起来
msg.arg1 = i;
try {
//程序休息1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
/**
* handler将消息发送到消息队列中,
* 当消息发送到消息队列中后,handler会触发handleMessage()方法来处理消息
*/
updateBarHandler.sendMessage(msg);
}
};
//按键事件
public boolean onKeyUp(int keyCode, KeyEvent event) {
//当按键为回退键是接受这个activity
if (keyCode == KeyEvent.KEYCODE_BACK) {
Activity2.this.finish();
}
return true;
};
}
新创建一个activity布局文件,activity2.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Activity2" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello"/>
<ProgressBar
android:id="@+id/bar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone"/>
<Button android:id="@+id/btn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/ok"></Button>
</LinearLayout>
修改AndroidManifest.xml文件
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<!--只需要修改入口程序为com.example.Activity2-->
<activity
android:name="com.example.Activity2"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
运行程序界面如下:
[img]http://dl.iteye.com/upload/attachment/0083/2398/82fe031a-55fb-3b2a-b759-d92d8de003da.png[/img]
点击ok按钮后,程序进度条每隔一秒就会更新进度,后台输出如下:
mian thread id:1
thread id:1 process bar 10
thread id:1 process bar 20
thread id:1 process bar 30
thread id:1 process bar 40
thread id:1 process bar 50
thread id:1 process bar 60
thread id:1 process bar 70
thread id:1 process bar 80
thread id:1 process bar 90
thread id:1 process bar 100
thread id:1 process bar end
从输出结果我们可以看到,handler的这种消息传递的异步处理都是在id为1的线程中完成整个handler过程,整个过程实际上是单线程处理的,没有真正实现异步化处理,如果要实现handler消息异步化处理可以通过HandlerThread来实现。
[b]3 Handler的线程异步[/b]
基于2中的程序稍作修改可以实现Handler的线程异步处理消息功能。
新创建一个activity实现如下:
package com.example;
import com.example.test_exp_14.R;
import android.annotation.SuppressLint;
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.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
@SuppressLint("HandlerLeak")
public class Activity3 extends Activity{
//开始按钮
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity2);
//根据id获取控件对象
btn = (Button)findViewById(R.id.btn);
//给开始按钮设置事件监听器
btn.setOnClickListener(btnClick);
}
//开始按钮事件监听器
OnClickListener btnClick = new OnClickListener() {
@Override
public void onClick(View v) {
System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getId());
/**
* 创建handlerThread对象,并启动该对象。
* 只有启动该对象才能通过handlerThread对象中的looper对象,否则获取不到looper对象
*/
HandlerThread handlerThread = new HandlerThread("handerThread");
handlerThread.start();
//通过handlerThread的looper对象来创建handler对象
MyHander myHandler = new MyHander(handlerThread.getLooper());
//通过handler对象获取msg对象
Message msg = myHandler.obtainMessage();
/**
* bundle可以保存消息传送信息,类似java中的hashmap,
* bundle的key只能为string类型,value只能为基本类型和常见的引用类型
*/
Bundle bundle = new Bundle();
bundle.putString("name", "xmong");
bundle.putInt("age", 20);
//设置msg对象的bundle数据,并将消息发送出去
msg.setData(bundle);
msg.sendToTarget();
}
};
//内部类handler对象
class MyHander extends Handler{
public MyHander(Looper looper){
super(looper);
}
/**
* 当消息队列中有消息时handler会触发该方法来对消息进行处理
*/
@Override
public void handleMessage(Message msg) {
System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getId());
//通过消息对象获取bundle数据
Bundle bundle = msg.getData();
System.out.println("name:"+bundle.getString("name"));
System.out.println("age:"+bundle.getInt("age"));
}
}
}
修改AndroidManifest.xml文件的程序入口为Activity3
运行程序后点击OK按钮,后台输出如下:
main:1
handerThread:9
name:xmong
age:20
从输出结果可以看到activity的主线程id号为1,而消息处理线程的id号为9。整个handler过程由两个线程参与,主线程负责发生消息,而handerThread线程负责处理处理消息。