案例:我们要实现的功能是点击按钮开始计时,从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 *
*/
初学者,希望大家一起交流分享经验!