刚开始学的时候,看见handler或者thread就开始犯蒙,其实不难的东西就是自己理不清思路。因为我是自学的,很多知识都只是囫囵吞枣,简单记录一下我理解的线程,算是自己的梳理,也给像我这样的初学者一些启发。
说一个形象一点的解释,线程就好比我们让别人帮我们干活:我现在在这里打字,口渴了,想让另一个人帮我拿杯水,我就好比是主线程,我还是在这里做我的事情,另外帮我拿水的就好比我的子线程,既不耽误我继续做我的工作,又能解决我不想做的浪费时间的事情。
一个android应用就是一个Linux进程,每个应用在各自的进程中运行,互不干扰,比较安全。
一个应用对应一个主线程,就是通常所说的UI线程,android遵守的就是单线程模型,所以说Ui操作不是线程安全的。在 单线程的模型下,一些耗时的操作就要交给其它子线程去执行。于是就有了Message Queue(消息队列),辅助线程间进行通信。而线程,就是为了解决我们遇到的浪费时间的事情,如果把一些耗时的操作放到主线程中就会造成 ANR(ANR:Application Not Responding,应用程序无响应)。每个线程都可以有自己的Message Queue,每个MessageQueue都会有一个对应的handler,其它子线程中要想有自己的消息队列必须手动生成。管理消息队列的是 Looper,每个进程都有自己的Looper。子线程中Message Queue 的生成必须依赖于Looper,Looper一旦开始loop后,它就会一直监控着消息队列,对send进来的Message进行处理。message的 处理采用先进先出原则。一旦处理完一条Message,那么该Message马上就会被置为null。当传送过来很多的消息时,不知道交给哪个线程执行 时,可以判断当前这个传送消息过来的handler里面的Looper对象是属于哪个线程的,属于哪个线程就在哪个线程里执行。
不知道大家是不是被上面的话绕晕了,简单的说,程序运行时只能有一个主线程但可以有若干个子线程。UI线程就是MainThread主线程,而其他的线程就属于WorkThread,我们在WorkThread中通过Handler发送消息Msg,消息放到消息队列中,Looper取出消息并交给Handler来处理,而转交给Handler处理时,就回到了MainThread中,我们就可以进行一些UI的操作了。至此,就建立起了WorkThread到MainThread的通讯机制。
下面我们就以倒计时为例,来简单了解线程的用法。首先要为按钮绑定一个监听:
bt1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (timestopflag) {
timestopflag = false;
// 生成一个线程对象
Thread timethread = new TimeThread();
// 启动线程
timethread.start();
bt1.setText("暂停计时");
} else {
timestopflag = true;
bt1.setText("开始计时");
}
}
});
之后新建一个线程,将秒数时间传进去,让线程沉睡,每过一秒减一秒。(不知道为什么这一段一写成代码格式就保存不了)
public void run() {
while (true) {
if (timestopflag) {
break;
}
String timestr = null;
try {
Thread.sleep(1000);
time = time - 1000;
if (time < 0) {
time = 0;
break;
}
timestr = TimeFmort(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Message msg = new Message();
// 用handler获取一个message对象
Message msg = handler.obtainMessage();
// 将时间传给msg
msg.obj = timestr;
// 将message发送到消息队列,交由handleMessage处理消息对象
handler.sendMessage(msg);
}
}
private String TimeFmort(long time) {
String timestr;
Date date = new Date(time);
String second, mit;
if (date.getMinutes() < 10) {
mit = "0" + date.getMinutes();
} else {
mit = date.getMinutes() + "";
}
if (date.getSeconds() < 10) {
second = "0" + date.getSeconds();
} else {
second = date.getSeconds() + "";
}
timestr = "0" + (date.getHours() - 8) + ":" + mit + ":" + second;
return timestr;
};
最后我们新建一个handler,接受到线程传过来的msg,并进行处理。
Handler handler = new Handler() {
public void handleMessage(Message msg)
// 接受到线程传过来的msg,并进行处理
String time = msg.obj.toString();
if (time.equals("00:00:00")) {
tv1.setText("计时结束");
} else {
tv1.setText(msg.obj.toString());
}
};
};
上 面是一个简单是倒计时的例子,TimeThread就是一个子线程,我们让线程沉睡,每1秒减少一次,并把秒数转换成00:00:00格式的字符串 timestr,在子线程中,通过Message msg = handler.obtainMessage();获取message对象(或者Message msg = new Message();创建一个对象,我还不知道这俩有啥不一样),把时间数据通过msg.obj = timestr;放入msg里 ,通过handler.sendMessage(msg);发送出去。handleMessage方法接到数据就可以更新textview里面是时间啦, 这样一个简单的线程传送消息就完成了。
如果我哪里写的不对或者不明白,欢迎大家留言指正,不胜感激~