案例:我们要实现的功能是点击按钮开始计时,从0开始计时到10停止,点击Main线程不会影响计时操作,运行如下
上面,大家也看到了,我使用了不同的方式来实现这个功能,下面跟大家来分享一下:
第一种方式:使用Handler中的postDelayed方法:
/**
* 使用Handler中的postDelayed计时
* @author Administrator
*
*/
class Button1ClickListener implements OnClickListener{
@Override
public void onClick(View v) {
//我们没有调用countTime的start方法,所以它不能当做线程来处理
handler1.post(countTime);
//我们还可以使用如下代码来终止计时
//handler.removeCallbacks(countTime);
}
}
Handler handler1=new Handler();
Runnable countTime=new Runnable() {
int count=0;
@Override
public void run() {
if(count<10){
//打印出来和MainThread一样
System.out.println("CountTime--->"+Thread.currentThread().getId());
count++;
show.setText("计时开始:"+count);
//1s钟后再次执行countTime
handler1.postDelayed(countTime, 1000);
}
}
};
第二种方式:使用Handler中的sendMessage方法:
/**
* 使用Handler中的sendMessage进行计时
* @author Administrator
*
*/
class Button2ClickListener implements OnClickListener{
@Override
public void onClick(View v) {
countTimeThread.start();
}
}
Thread countTimeThread=new Thread(){
int count=0;
public void run() {
while(count<10){
try {
Thread.sleep(1000);
//打印出来和MainThread不同
System.out.println("countTimeThread-->"+Thread.currentThread().getId());
count++;
//使用以下几种方式都可以
Message msg=new Message();
//Message msg=Message.obtain();
//Message msg=handler2.obtainMessage();
msg.what=UPDATE;
msg.obj=count;
handler2.sendMessage(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
};
Handler handler2=new Handler(){
@Override
public void handleMessage(Message msg) {
//打印出来和MainThread一样
System.out.println("handler2-->"+Thread.currentThread().getId());
if(msg.what==UPDATE){
show.setText("计时开始:"+msg.obj);
}
}
};
第三种方式:使用Handler中的sendMessageDelayed方法:
/**
* 使用Handler中的sendMessageDelayed方法计时
* @author Administrator
*
*/
class Button3ClickListener implements OnClickListener{
@Override
public void onClick(View v) {
Message msg=handler3.obtainMessage(UPDATE);
handler3.sendMessageDelayed(msg, 1000);
}
}
final Handler handler3=new Handler(){
int count=0;
public void handleMessage(Message msg) {
if(count<=10){
if(msg.what==UPDATE){
show.setText("计时开始:"+count);
}
Message message=handler3.obtainMessage(UPDATE);
handler3.sendMessageDelayed(message, 1000);
count++;
}
};
};
第四中方式:使用AsyncTask
1)创建一个CountTimeAsyncTask继承自AsyncTask:
package com.xin.test;
import android.os.AsyncTask;
import android.widget.TextView;
public class CountTimeAsyncTask extends AsyncTask<Void, Integer, String>{
private TextView textView;
public CountTimeAsyncTask(TextView textView){
this.textView=textView;
}
//该方法在UI线程中执行execute方法时会首次被调用,一般用来完成UI的初始化操作
//该方法运行在UI线程中
@Override
protected void onPreExecute() {
super.onPreExecute();
}
//执行完onPreExecute方法后,会执行下面的这个方法,传入的边长参数是在execute方法中传递过来的
//注意如果是Void,在execute方法中所带的参数为null,如果不带参数会报错
//该方法不运行在UI线程中
@Override
protected String doInBackground(Void... params) {
int count=0;
while(count<10){
publishProgress(count);//调用该方法一次,下面的onProgressUpdate会被执行一次
try {
Thread.sleep(1000);
count++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return count+"";
}
//执行这个方法,可以用来更新UI中控件的变化,例如进度条信息变化等等
//该方法运行在UI线程中
@Override
protected void onProgressUpdate(Integer... values) {
int count=values[0];
System.out.println(3);
textView.setText("计时开始:"+count);
}
//doInBackground方法执行完后会执行该方法,可以用来提示用户异步操作结束
@Override
protected void onPostExecute(String result) {
textView.setText("计时结束-->"+result);
}
}
2)在UI线程中实例化CountTimeAsyncTask,并调用其execute方法执行该异步操作:
/**
* 使用AsyncTask进行计时
* @author Administrator
*
*/
class Button4ClickListener implements OnClickListener{
@Override
public void onClick(View v) {
//调用后只会执行一次
AsyncTask countTimeTask=new CountTimeAsyncTask(show);
//因为doInBackground中的参数为Void... params,所以这里必须传递参数,否则会报错
countTimeTask.execute(null);
//打印出和MainThread一样
System.out.println("asyncTask--->"+Thread.currentThread().getId());
}
}
我们在主线程操作按钮中执行的代码就是一个吐司操作:
/**
* 主线程操作
* @author Administrator
*
*/
class Button5ClickListener implements OnClickListener{
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "我是主线程", Toast.LENGTH_LONG).show();
}
}
计时操作总结:
/**
* 计时操作
* 用第一种方式使用的是Handler中的postDelayed计时,因为里面设置的参数中Runnable我们并没有调用其实例化(countTime)的start方法,
* 所以这里并不是线程,所以能够进行更新UI主线程操作,此时的Handler与Main处于同一线程中,也就是主线程中,所以能够更新UI
* 用第二种方式使用的是Handler中的handMessage计时,我们用到了线程操作countTimeThread,所以更新线程的操作不能在线程中进行
* 我们应该发送一个消息(sendMessage)交给Handler去处理,此时的Handler线程与Main线程处于同一线程中
* 第三种方式使用Handler中的sendMessageDelayed发送消息,相隔多少时间发送,此时的Handler也是与Main处于同一线程中
* 用第四种方式使用的是继承AsyncTask类,然后调用其execute方法进行计时操作,里面的操作和线程状况可参考前面的实例代码
* 注意Activity中的单线程模式:所有的UI操作都是非线程安全的,并且我们只能在主线程(UI)线程中对UI进行更新操作
* @author HarderXin *
*/
初学者,希望大家一起交流分享经验!