AsyncTask是Android为了简化异步操作而封装的异步任务操作抽象类。当我们需要在程序中执行耗时的异步操作时,我们可以考虑使用AsyncTask来实现。

AsyncTask的使用比较简单,由于AsyncTask是一个抽象类,我们需要写一个类来继承AsyncTask,继承AsyncTask需要指定三个泛型参数,参数分别表示为:
(1)Params:在执行AsyncTask时需要传入的参数,比如我们输入的String类型URL
(2)Progress:后台任务执行中返回的进度值类型,如果需要在界面上显示当前进度,则就用Progress指定的泛型作为进度单位。
(3)Result:耗时操作完成后返回的结果,如果需要对结果进行返回,那么就用这里指定的泛型作为返回的类型。

实现AsyncTask类还需要重写相应的回调方法,一般我们用到的有如下四个方法,他们都是自动被调用的,记得不要手动的调用:
(1)doInBackground(Void… params):必须重写,异步执行耗时操作
(2)onPreExecute():执行耗时操作前被调用,通常用来完成一些初始化操作
(3)onProgressUpdate(Void… values):将doInBackground方法返回的值传递给该方法,在doInBackground中调用publishProgroess()方法可以且来更新进度
(4)onPostExecute(Void result):耗时的异步任务完成后回调该方法

需要说明一点:这几个方法中,只有doInBackground方法是在子线程中执行的,其他的方法都是在主线程中执行的。

启动和取消这个异步任务的方法分别是:
(1)myAsyncTask.execute() 其中该任务
(2)myAsyncTask.cancel() 取消该任务

我们已经大概了解了AsyncTask的基础知识,接下来就以如下三个点做一些实例,加深一下印象。

(一)观察AsyncTask子类方法的执行顺序
首先写一个最简单的AsyncTask子类,传入的参数都是空值, 然后在每一个方法中都打印出一句话,主要是为了便于观察他们的执行顺序。

package com.adan.asynctaskdome;import android.os.AsyncTask;import android.util.Log;/** * @author: xiaolijuan * @description: * @projectName: AsyncTaskDome * @date: 2016-03-04 * @time: 12:47 */public class MyAsyncTask extends AsyncTask<Void, Void, Void> {    @Override    protected Void doInBackground(Void... params) {        Log.d("TAG", "doInBackground");        return null;    }    @Override    protected void onPreExecute() {        Log.d("TAG", "onPreExecute");        super.onPreExecute();    }    @Override    protected void onPostExecute(Void aVoid) {        Log.d("TAG", "onPostExecute");        super.onPostExecute(aVoid);    }    @Override    protected void onProgressUpdate(Void... values) {        Log.d("TAG", "onProgressUpdate");        super.onProgressUpdate(values);    }}

MainActivity的代码

package com.adan.asynctaskdome;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.widget.Button;public class MainActivity extends Activity implements View.OnClickListener {    private Button button1, button2, button3;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        new MyAsyncTask().execute();    }}

运行结果:

这里的 方法没有执行,是因为我们需要在doInBackground(Void… params)中提供publishProgress(Progress…)方法用于显示进度信息,如下所示:

package com.adan.asynctaskdome;import android.os.AsyncTask;import android.util.Log;/** * @author: xiaolijuan * @description: * @projectName: AsyncTaskDome * @date: 2016-03-04 * @time: 12:47 */public class MyAsyncTask extends AsyncTask<Void, Void, Void> {    @Override    protected Void doInBackground(Void... params) {        Log.d("TAG", "doInBackground");        publishProgress();        return null;    }    @Override    protected void onPreExecute() {        Log.d("TAG", "onPreExecute");        super.onPreExecute();    }    @Override    protected void onPostExecute(Void aVoid) {        Log.d("TAG", "onPostExecute");        super.onPostExecute(aVoid);    }    @Override    protected void onProgressUpdate(Void... values) {        Log.d("TAG", "onProgressUpdate");        super.onProgressUpdate(values);    }}

运行效果:

从打印的结果很容易就看出方法的执行顺序了吧,如下:

onPreExecute——>onProgressUpdate(调用了publishProgress方法才会调用该方法)——>doInBackground——>onPostExecute
(二)异步加载网络图片
首先一点先别忘记了,我们既然是要访问网络,千万不能忘记了在配置文件中添加网络权限哦

<uses-permission android:name="android.permission.INTERNET" />

LoadBitmapActivity,我们使用一个ImageView用来加载我们的这张网络图片的,然后再在中间放置一个进度条,用来显示进程
LoadBitmapActivity

package com.adan.asynctaskdome;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.AsyncTask;import android.os.Bundle;import android.view.View;import android.widget.ImageView;import android.widget.ProgressBar;import java.io.BufferedInputStream;import java.io.IOException;import java.io.InputStream;import java.net.URL;import java.net.URLConnection;/** * @author: xiaolijuan * @description: 加载图片 * @projectName: AsyncTaskDome * @date: 2016-03-04 * @time: 13:12 */public class LoadBitmapActivity extends Activity {    private ImageView img;    private ProgressBar progressBar;    private static final String url = "https://www.baidu.com/img/bd_logo1.png";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_load_bitmap);        img = (ImageView) findViewById(R.id.img);        progressBar = (ProgressBar) findViewById(R.id.progressbar);        new MyAsyncTask().execute(url);    }    class MyAsyncTask extends AsyncTask<String, Void, Bitmap> {        /** * 将url所对应的图像解析成Bitmap * * @param params * @return */        protected Bitmap doInBackground(String... params) {            String url = params[0];// 获取传递进来的参数            Bitmap bitmap = null;            URLConnection connection;//定义网络连接对象            InputStream is;//用于获取数据的输入流            try {                //访问网络操作,耗时操作                connection = new URL(url).openConnection();//获取网络连接对象                is = connection.getInputStream();//获取输入流                BufferedInputStream bis = new BufferedInputStream(is);                bitmap = BitmapFactory.decodeStream(bis);//通过decodeStream()方法解析输入流,从而转换成一张bitmap图片                is.close();                bis.close();            } catch (IOException e) {                e.printStackTrace();            }            //将bitmap作为返回对象            return bitmap;        }        @Override        protected void onPreExecute() {            super.onPreExecute();            //显示进度条            progressBar.setVisibility(View.VISIBLE);        }        @Override        protected void onPostExecute(Bitmap bitmap) {            try {                Thread.sleep(2000);//为了观看效果,休眠2秒            } catch (InterruptedException e) {                e.printStackTrace();            }            super.onPostExecute(bitmap);            //关闭进度条和更新UI            progressBar.setVisibility(View.GONE);            img.setImageBitmap(bitmap);        }    }}

activity_load_bitmap.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">    <ImageView  android:id="@+id/img" android:layout_width="200dp" android:layout_height="200dp" android:layout_centerInParent="true" />    <ProgressBar  android:id="@+id/progressbar" android:layout_width="70dp" android:layout_height="70dp" android:layout_centerInParent="true" /></RelativeLayout>

效果图如下:

(三)显示进度
ShowProgressActivity,用来显示这个进度条,在这个类里面我们就使用AsyncTask让进度条动起来。

package com.adan.asynctaskdome;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.widget.ProgressBar;/** * @author: xiaolijuan * @description: 显示进度 * @projectName: AsyncTaskDome * @date: 2016-03-04 * @time: 13:12 */public class ShowProgressActivity extends Activity {    private ProgressBar progressBar;    private MyAsyncTask mTask;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_show_progress);        progressBar = (ProgressBar) findViewById(R.id.progressBar);        mTask = new MyAsyncTask();        mTask.execute();    }    class MyAsyncTask extends AsyncTask<Void, Integer, Void> {        protected Void doInBackground(Void... params) {            for (int i = 0; i < 100; i++) {                publishProgress(i);                try {                    Thread.sleep(100);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            return null;        }        //根据任务执行情况更新UI,其实就是更新进度条        protected void onProgressUpdate(Integer... values) {            super.onProgressUpdate(values);            // 进度条数值显示            progressBar.setProgress(values[0]);        }    }}

activity_show_progress,布局文件很简单,里面就放置一个横向的进度条而已

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center">    <ProgressBar  android:id="@+id/progressBar" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="5dp" /></LinearLayout>

效果图如下:

不知道大家发现一个问题没,当我第一次点击界面时候,进度条还没运行完,我就返回了,当再一次进去时候,等待了好久进度条才有开始启动起来。这是因为我们之前的doInBackground里的线程还在进行,循环还在继续,所以AsyncTask还在执行。因此此刻重新进入进度条界面时,就不可能立刻启动新的AsyncTask,而旧的呢又因为之前我们返回到按钮界面就没法重新绘制了。所以只有等旧的AsyncTask执行完毕,才会开启新的。就像队列一样,只有运行完之后才运行下一个。这时候你会想,那就麻烦了,如果我需要大量地处理一些耗时操作呢,这样给用户的体验性是不好的。我们能不能在我们点击返回的时候就取消了这个任务呢,答案当然是可以的,只不过我们需要将AsyncTask与Activity的生命周期相关联。
我把修改后的代码贴一下:

package com.adan.asynctaskdome;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.widget.ProgressBar;/** * @author: xiaolijuan * @description: 显示进度 * @projectName: AsyncTaskDome * @date: 2016-03-04 * @time: 13:12 */public class ShowProgressActivity extends Activity {    private ProgressBar progressBar;    private MyAsyncTask mTask;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_show_progress);        progressBar = (ProgressBar) findViewById(R.id.progressBar);        mTask = new MyAsyncTask();        mTask.execute();    }    @Override    protected void onPause() {        // 判断当前异步任务是否在进行中        if (mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING) {            // cancel()方法:取消该任务,但只是将对应的AsyncTask状态标记为cancel状态,并没有真正取消异步操作            mTask.cancel(true);        }        super.onPause();    }    class MyAsyncTask extends AsyncTask<Void, Integer, Void> {        protected Void doInBackground(Void... params) {            for (int i = 0; i < 100; i++) {                if (isCancelled()) {//如果异步任务为取消状态,立刻break,跳出循环                    break;                }                publishProgress(i);                try {                    Thread.sleep(100);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            return null;        }        //根据任务执行情况更新UI,其实就是更新进度条        protected void onProgressUpdate(Integer... values) {            super.onProgressUpdate(values);            // 进度条数值显示            progressBar.setProgress(values[0]);        }    }}

接下来我们再看看效果图:

最后我们来总结一下使用AsyncTask类需要注意的几点:
(1)AsyncTask实例必须在UI Thread中创建;
(2)execute()方法也必须在UI Thread中调用;
(3)cancel()方法:取消该任务,该方法只是将对应的AsyncTask状态标记为cancel状态,并没有真正取消异步操作;
(4)每个AsyncTask的execute()方法只能被执行一次,否则多次调用时将会出现异常;
(5)重写的四个方法是系统自动调用,不能手动更改;

如果存在理解偏差甚至错误的地方,请多多交流指正!谢谢各位!
点击下载源代码:Android AsyncTask基础

更多相关文章

  1. Android异步加载图像小结(含线程池,缓存方法)[转]
  2. ubuntu下eclipse Android(安卓)ADT中SDK Manager中安装SDK失败的
  3. 3D激光扫描三维重建——6.(android)系统框架
  4. eclipse新建android工程出现This template depends on Android(
  5. Android下生成core dump的方法
  6. Android画图之抗锯齿
  7. [置顶] Android(安卓)从硬件到应用:一步一步向上爬 4 -- 使用 JNI
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. Android(安卓)数据存储(二) 文件的使用
  2. android 代码生成布局
  3. StevGuo系列文章翻译之Android内存泄漏检
  4. 无需 root 实现在 Android(安卓)设备上运
  5. Android上使用libgdx
  6. 在Ubuntu上下载编译安装Android最新内核
  7. 详解Android核心模块及相关技术
  8. Android——编译release版签名系统
  9. Android恶意软件特征及分类
  10. Android访问网络,使用HttpURLConnection还