最近任务比较少,基本没遇到什么特殊的要处理的东西,所以就写一写一些基础的东西,温故而知新是各位前辈们一项提倡的意见。
消息机制是android学习的一个重要的模块,不过还是那句话,重要并不代表它很难。
在android操作系统中存在着消息队列的操作,用消息队列可以完成主线程和子线程之间的消息传递,要完成这些线程的消息操作,则需要使用android.os包中Looper、Message、Handle三个类。
Message类:这个类的主要功能是进行消息的封装。在消息当中使用最多的是what和obj两个变量。
1、what变量指明一个Message所携带的是何种信息。
2、而通过obj传递信息。
Handler类:一般消息的操作则需要Handler完成。而操作Handler的对象就是主线程(UI线程)与子线程。
Looper类:Looper类号称是消息的通道,使用Handler处理Message时,都是需要依靠一个Looper通道完成的,在一个Activity类中,会自动帮助用户启动Looper对象,而若是在自定义的类中,则需要用户手工调用Looper类中的若干方法。
PS:关于Looper、Message和Handler的另一种解释。
行天曾看到一个很经典的解释,如果把Looper比喻成一个正在排队买票的队伍,那么每一个排队的人就是一个Message,而一个维护队伍的管理员就相当于一个Handler,管理员负责通知对外的人进到队列之中等待,也负责通知队列中的人离开队列。
下面则通过一个滚动条的例子来具体了解一下这三个类的关系。
package com.example.progressbar;
import java.util.Timer;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.ProgressBar;
import android.widget.TextView;
public class WelcomeActivity extends Activity {
private ProgressBar myProBar;//定义进度条
private TextView info1;//定义信息1
private Timer timer;//定义一个时间类
private Handler myHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.welcome);
myProBar = (ProgressBar)this.findViewById(R.id.welcome_probar_myprobar);//实例化进度条
info1 = (TextView)this.findViewById(R.id.welocome_text_show1);//实例化信息1
myHandler = new MainHandler(this);
timer = new Timer();//定义时间 子线程
timer.schedule(new LoadTimerTask(myHandler), 0, 30);//立即开始,每隔30毫秒增长
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
WelcomeActivity.this.myHandler.getLooper().quit();//结束队列
}
public TextView getInfo1() {
return info1;
}
public void setInfo1(TextView info1) {
this.info1 = info1;
}
public Timer getTimer() {
return timer;
}
public void setTimer(Timer timer) {
this.timer = timer;
}
public ProgressBar getMyProBar() {
return myProBar;
}
public void setMyProBar(ProgressBar myProBar) {
this.myProBar = myProBar;
}
}
package com.example.progressbar;
import java.util.TimerTask;
import android.os.Handler;
import android.os.Message;
public class LoadTimerTask extends TimerTask{
private int index = 0;//用于显示百分比
private Handler handler;//定义handler用于传输百分比
public LoadTimerTask(Handler handler) {
// TODO Auto-generated constructor stub
this.handler = handler;
}
@Override
public void run() {
// TODO Auto-generated method stub
index ++;
Message message = new Message();
message.what = index;//将百分比放到message当中
handler.sendMessage(message);//子线程将message放到handler中
}
}
package com.example.progressbar;
import java.util.Timer;
import android.app.Activity;
import android.os.Handler;
import android.os.Message;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainHandler extends Handler {
private Activity activity;
public MainHandler(Activity activity) {
// TODO Auto-generated constructor stub
this.activity = activity;
}
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
int progress = msg.what;
WelcomeActivity welcomeActivity = (WelcomeActivity)activity;
TextView info1 = welcomeActivity.getInfo1();
switch(progress)
{
case 20:
{
info1.setText("欢迎您 ");
welcomeActivity.setInfo1(info1);
break;
}
case 50:
{
info1.setText("欢迎您来到 ");
welcomeActivity.setInfo1(info1);
break;
}
case 80:
{
info1.setText("欢迎您来到51比购网!");
welcomeActivity.setInfo1(info1);
break;
}
case 100:
{
Timer timer = welcomeActivity.getTimer();
timer.cancel();
welcomeActivity.setTimer(timer);
System.out.println("timer被干掉");
}
}
ProgressBar myProBar = welcomeActivity.getMyProBar();
myProBar.setProgress(progress);
welcomeActivity.setMyProBar(myProBar);//将数据设置进去
}
}
以上是一个老土的例子,原理也很简单。
首先,主线程(UI线程)实例化handler对象以及调度器,之后调用调度器的实现类(子线程)。
其次,在子线程中实现消息(Message)的生成,并用Handler将消息返回到主线程。
再次,在自定义的handler类当中进行数据的处理,并控制ProgressBar以及TextView的处理。
不过,今天行天要讲的重点根本就不是这个故事。
在实际开发中,当我们用到消息控制的时候会有千奇百怪的问题,比如说细心的同学会问,为什么一定要在子线程当中把消息传给Handler然后在处理主线程的组件,干嘛不在子线程当中直接处理控制住线程的组件。
简单修改一下代码。
@Override
public void run() {
// TODO Auto-generated method stub
index ++;
Message message = new Message();
message.what = index;//将百分比放到message当中
handler.sendMessage(message);//子线程将message放到handler中
WelcomeActivity welcomeActivity = (WelcomeActivity)activity;
TextView textView = welcomeActivity.getInfo1();
textView.setText(index);
welcomeActivity.setInfo1(textView);
}
结果就会发现报错:
问题2:当时我看到这段代码的时候,我第一个反应就是,Looper呢?Looper怎么没了,难不成这就是传说中的配角组件?
答:其实以上的这段代码并非我们所看到的表面现象,其中省略了一些东西。因为我们现在是由Activity直接发送消息的,所以在Handler的子类中会自动帮助用户创建好要操作的Looper对象。如果用户使用自定义的线程类,就要由用户自己进行Looper对象的维护操作了。
添加一个ChildThread类用作测试
package com.example.progressbar;
import android.app.Activity;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
public class ChildThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
Message message = new Message();
message.what = 8080;
Looper.prepare();
Handler childHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
System.out.println(msg.what);
}
};
childHandler.sendMessage(message);
Looper.loop();
}
}
结果很正常。
在本段程序中最重要的部分就是Looper对象操作的prepare()和loop()方法,如果没有这两方法,将无法通过子线程创建Looper,也就无法传递消息。
结果就会报这种错误。