AsyncTask
AsyncTask也可以像Handler一样,在子线程中对UI进行更新,不过他实现的原理也是基于异步消息处理机制.
首先看一下AsyncTask的基本用法,AsyncTask是一个抽象类,必须要一个子类去继承他,在继承的时候,我们可以为AsyncTask类指定三个泛型参数,这三个参数的用途如下:
1.Params
在执行AsyncTask时需要传入的参数,可用于在后台任务中使用,
2.Progress
后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位.
3.Result
当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型
在下面的例子中,我可以这样定义:
private class MyTask extends AsyncTask<String, Integer, String>{}
第一个泛型参数指定为String,表示在执行AsyncTask的时候需要传入String类型的参数,第二个参数定义为Integer,表示使用整形数据来作为进度显示单位,第三个参数也是String,则表示使用String来反馈执行结果.
接着,我们在重写AsyncTask中的几个方法才能完成对任务的定制.
onPreExecute():这个方法会在任务开始之前调用,用于进行一些界面上的初始化工作,比如显示一个进度条对话框等.
doInBackground(Params...)这个方法中的所有代码都会在子线程中运行,所以,所有耗时逻辑都应该在这里处理,任务一旦完成就可以通过return语句将任务的执行结果返回,如AsyncTask的第三个泛型参数指定的是Void,就可以不返回任务执行结果,注意:在这个方法中是不可以进行UI操作的。如需要实时更新UI元素,可以调用publicProgress(Progress ...)方法来完成
onProgressUpdate(Progress...) 当在doInBackground()方法中调用了publicProgress()方法时,这个方法将会很快调用,方法中携带的参数就是在后台任务中传递过来的,在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应地更新.参数类型就是对应于AsyncTask<String, Integer, String>中的第二个.
onPostEcecute(Result) 当后台任务(doInBackground)执行完毕并通过return语句进行返回时,这个方法就很快会调用,返回的数据就会作为参数传递到此方法中,可以利用返回的数据来进行一些UI操作,比如提醒任务执行结果,以及关闭进度条对话框。
onCancelled 表示在取消asyncTask任务时的回调,可以对取消任务时,UI的一些操作,
废话说了这个多,不来个例子怎么行?
新建一个项目,修改MainActivity代码如下:activity_main.xml文件:public class MainActivity extends Activity { private static final String TAG = "ASYNC_TASK"; private Button execute; private Button cancel; private ProgressBar progressBar; private TextView textView; private MyTask mTask; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); execute = (Button) findViewById(R.id.execute); execute.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //注意每次需new一个实例,新建的任务只能执行一次,否则会出现异常 mTask = new MyTask(); mTask.execute("http://www.baidu.com"); execute.setEnabled(false); cancel.setEnabled(true); } }); cancel = (Button) findViewById(R.id.cancel); cancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //取消一个正在执行的任务,onCancelled方法将会被调用 mTask.cancel(true); } }); progressBar = (ProgressBar) findViewById(R.id.progress_bar); textView = (TextView) findViewById(R.id.text_view); } private class MyTask extends AsyncTask<String, Integer, String> { //onPreExecute方法用于在执行后台任务前做一些UI操作 @Override protected void onPreExecute() { Log.i(TAG, "onPreExecute() called"); textView.setText("loading..."); } //doInBackground方法内部执行后台任务,不可在此方法内修改UI @Override protected String doInBackground(String... params) { Log.i(TAG, "doInBackground(Params... params) called"); try { HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(params[0]); HttpResponse response = client.execute(get); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { HttpEntity entity = response.getEntity(); InputStream is = entity.getContent(); long total = entity.getContentLength(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buf = new byte[1024]; int count = 0; int length = -1; while ((length = is.read(buf)) != -1) { baos.write(buf, 0, length); count += length; //调用publishProgress公布进度,最后onProgressUpdate方法将被执行 publishProgress((int) ((count / (float) total) * 100)); //为了演示进度,休眠500毫秒 Thread.sleep(500); } return new String(baos.toByteArray(), "utf-8"); } } catch (Exception e) { Log.e(TAG, e.getMessage()); } return null; } //onProgressUpdate方法用于更新进度信息 @Override protected void onProgressUpdate(Integer... progresses) { Log.i(TAG, "onProgressUpdate(Progress... progresses) called"); progressBar.setProgress(progresses[0]); textView.setText("loading..." + progresses[0] + "%"); } //onPostExecute方法用于在执行完后台任务后更新UI,显示结果 @Override protected void onPostExecute(String result) { Log.i(TAG, "onPostExecute(Result result) called"); textView.setText(result); execute.setEnabled(true); cancel.setEnabled(false); } //onCancelled方法用于在取消执行中的任务时更改UI @Override protected void onCancelled() { Log.i(TAG, "onCancelled() called"); textView.setText("cancelled"); progressBar.setProgress(0); execute.setEnabled(true); cancel.setEnabled(false); } } }
因为Demo中用到了网络请求,所以,需要网络权限,<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <Button android:id="@+id/execute" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="execute"/> <Button android:id="@+id/cancel" android:layout_width="fill_parent" android:layout_height="wrap_content" android:enabled="false" android:text="cancel"/> <ProgressBar android:id="@+id/progress_bar" android:layout_width="fill_parent" android:layout_height="wrap_content" android:progress="0" android:max="100" style="?android:attr/progressBarStyleHorizontal"/> <ScrollView android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/text_view" android:layout_width="fill_parent" android:layout_height="wrap_content"/> </ScrollView> </LinearLayout>
效果如下图:<uses-permission android:name="android.permission.INTERNET"/>
依次是:任务未开始,任务进行中(任务暂停),任务结束
源码