千家信息网

AsyncTask怎么用

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,这篇文章主要介绍了AsyncTask怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。引言AsyncTask,相信大家已经很熟悉了。
千家信息网最后更新 2026年11月01日AsyncTask怎么用

这篇文章主要介绍了AsyncTask怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

引言

AsyncTask,相信大家已经很熟悉了。它的内部封装了Thread和Handler,这让我们可以将一些耗时操作放到AsyncTask,并且能将结果及时更新到UI上。AsyncTask主要用于短时间耗时操作,长时间耗时操作不建议使用AsyncTask。

一个例子

private class DownloadFilesTask extends AsyncTask {  protected void onPreExecute() {        showProgress();  }  protected Long doInBackground(URL... urls) {      int count = urls.length;      long totalSize = 0;      for (int i = 0; i < count; i++) {          totalSize += Downloader.downloadFile(urls[i]);          publishProgress((int) ((i / (float) count) * 100));          // Escape early if cancel() is called          if (isCancelled()) break;      }      return totalSize;  }  protected void onProgressUpdate(Integer... progress) {      setProgressPercent(progress[0]);  }  protected void onPostExecute(Long result) {      showDialog("Downloaded " + result + " bytes");  } }复制代码

AsyncTask是一个抽象类,我们要使用时必须自定义一个类继承于它。AsyncTask的原型为:

public abstract class AsyncTask {}复制代码

它接收三个泛型参数,分别表示参数类型、进度类型、结果类型。

上述的例子中DownloadFilesTask接收参数类型为URL类型,使用Integer类型表示任务进度,最终的任务结果是一个Long类型。

注意:上面三个泛型类型不一定都得用一个明确的类型,对于没有使用的类型,可以使用Void类型代替。

继承AsyncTask至少需要重写doInBackground方法,同时AsyncTask也提供了另外三个方法供我们重写,分别是onPreExecute、onProgressUpdate、onPostExecute。

  • onPreExecute方法。在任务开始执行之前执行,它运行在UI线程中。通常我们可以在这里展示一个等待进度条。

  • doInBackground方法。贯穿整个耗时任务,它运行在子线程中。在这里执行耗时操作。

  • onProgressUpdate方法。贯穿整个耗时任务,在publishProgress方法被调用后执行,它运行在UI线程中。通常用于展示整个任务的一个进度。

  • onProgressUpdate方法。在任务接收后调用,doInBackground的返回结果会透传给onPostExecute的参数值,它运行在主线程中。通常我们从这里获取任务执行完成后的结果数据。

AsyncTask的规则

  • AsyncTask类必须在UI线程加载。(在4.1系统版本以上会自动完成)

  • AsyncTask对象必须在UI线程创建,也就是说AsyncTask的构造方法必须在UI线程中调用。(经过测试AsyncTask对象可以在子线程创建,只要保证execute方法在UI线程执行就OK的。但是没有人会这样做,因为多此一举!!!)

  • execute方法必须在UI线程中调用。这样做是保证onPreExecute方法运行在UI线程。

  • 不要主动调用onPreExecute、doInBackground、onProgressUpdate、onProgressUpdate方法。

  • 单线程下,AsyncTask对象的任务只能执行一次,否则会报运行时错误。

AsyncTask执行任务的规则

在AsyncTask诞生之初,任务是在一个后台线程中顺序执行的。从Android 1.6开始,就变成了可以在后台线程中并行执行任务。然后,到了Android 3.0版本,又改成了单线程顺序执行,以此避免并发任务产生的错误行为。

为了验证上述结论,下面看一个Demo例子。

public class MainActivity extends Activity {    public static final String TAG = "MyApplication";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        new MyTask("task1").execute();        new MyTask("task2").execute();        new MyTask("task3").execute();        new MyTask("task4").execute();        new MyTask("task5").execute();        new MyTask("task6").execute();    }    private class MyTask extends AsyncTask {        private String taskName;        MyTask(String taskName) {            this.taskName = taskName;        }        @Override        protected Void doInBackground(Void... integers) {            try {                Thread.sleep(6000);            } catch (InterruptedException e) {                e.printStackTrace();            }            return null;        }        @Override        protected void onPostExecute(Void aVoid) {            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");            Log.e(TAG, taskName + " finish at: " + df.format(new Date()));        }    }}复制代码

这个例子比较简单,就是在MainActivity启动时,执行了六次MyTask,并将任务执行后的时间节点打印出来。


image.png

手机的系统版本是Android 8.0,从上面的Log信息可以看出,AsyncTask的确是串行执行的。由于现有测试机最低系统版本都是Android 4.1,已经很难找到Android 3.0以下的老古董机子了????,所以我们只能通过源码去验证Android 1.6到Android 3.0期间,AsyncTask是否是并行执行的。

源码分析

Android 2.3版本

AsyncTask是否串行或者并行执行,取决于它的execute方法。

public final AsyncTask execute(Params... params) {    ...省略     mWorker.mParams = params;    sExecutor.execute(mFuture);    return this;}复制代码

而execute方法中通过sExecutor,实际为ThreadPoolExecutor对象,它的初始化如下所示。

private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,            MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);复制代码

ThreadPoolExecutor是一个多线程容器,其中可以创建多个线程来执行多个任务。由此验证了Android 1.6版本到Android 3.0版本直接,AsyncTask执行任务的机制的确也现在的机制不一样,它可以让任务并行执行。

Android 8.0版本

我们对比一下Android 8.0版本的execute方法。

public final AsyncTask execute(Params... params) {    return executeOnExecutor(sDefaultExecutor, params);}public final AsyncTask executeOnExecutor(Executor exec,        Params... params) {    ...省略    mWorker.mParams = params;    exec.execute(mFuture);    return this;}复制代码

execute方法中调用了executeOnExecutor方法,并将sDefaultExecutor作为Executor对象传递进去,sDefaultExecutor的初始化如下所示。

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;public static final Executor SERIAL_EXECUTOR = new SerialExecutor();private static class SerialExecutor implements Executor {    final ArrayDeque mTasks = new ArrayDeque();    Runnable mActive;    public synchronized void execute(final Runnable r) {        mTasks.offer(new Runnable() {            public void run() {                try {                    r.run();                } finally {                    scheduleNext(); //任务执行完毕后继续执行scheduleNext方法                }            }        });        if (mActive == null) { //第一个任务会执行该方法            scheduleNext();        }    }    protected synchronized void scheduleNext() {        if ((mActive = mTasks.poll()) != null) { //判断mTask队列中是否有下一个任务,有则取出来执行            THREAD_POOL_EXECUTOR.execute(mActive);        }    }}复制代码

可以看到,在Android 8.0版本中,创建了一个ArrayDeque队列,每次只从队列中获取一个任务执行,执行完毕后会继续判断队列中是否有任务,如果有则取出来执行,直到所有任务执行完毕为止。由此可见,Android 8.0版本执行任务是串行执行的。

如果我们想改变AsyncTask这种默认行为呢,可以修改么?答案是肯定的。

我们可以直接调用AsyncTask的executeOnExecutor方法,并将一个Executor对象传递过去,就能变成并行的执行方法了。

对于上面的例子,可以这样改动。

public class MainActivity extends Activity {    public static final String TAG = "MyApplication";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        new MyTask("task1").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);        new MyTask("task2").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);        new MyTask("task3").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);        new MyTask("task4").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);        new MyTask("task5").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);        new MyTask("task6").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);    }    private class MyTask extends AsyncTask {        private String taskName;        MyTask(String taskName) {            this.taskName = taskName;        }        @Override        protected Void doInBackground(Void... integers) {            try {                Thread.sleep(6000);            } catch (InterruptedException e) {                e.printStackTrace();            }            return null;        }        @Override        protected void onPostExecute(Void aVoid) {            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");            Log.e(TAG, taskName + " finish at: " + df.format(new Date()));        }    }}复制代码

执行后,打印出来的Log信息如下图所示。


image.png

注意:这里前五个Task是同时执行的,因为AsyncTask.THREAD_POOL_EXECUTOR创建了五个核心线程,第六个任务需要等待空闲线程才能继续执行。所以会出现第六个任务和前五个任务执行时间不一致的现象,特此说明。

感谢你能够认真阅读完这篇文章,希望小编分享的"AsyncTask怎么用"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

任务 方法 线程 版本 类型 代码 对象 运行 例子 结果 参数 篇文章 进度 队列 三个 同时 时间 系统 并将 验证 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网与科技 狮子座互联网科技 互联网科技公司怎么样 未来的互联网科技 狮子座互联网科技有限公司 互联网金融 科技创新 互联网科技股午盘股票涨跌 现代科技和互联网有关系吗 互联网教育科技公司vipkid 互联网科技寓意 团飞科技与伯堂互联网服务平台 重庆威客帮互联网科技 广西互联网科技孵化中心 本届互联网博览会上的黑科技 民营互联网公司国防科技 陕西云淼互联网科技公司 九思连强互联网电子科技有限公司 普陀区互联网教育科技管理办法 互联网科技和医药行业 平安好医生打造互联网科技医疗 互联网科技工作委员会主任 互联网核心科技是什么 科技互联网的估值 中国科技互联网公司收入 互联网教育科技公司vipkid 新兴科技互联网创新大赛颁奖典礼 河南住房之家互联网科技 华中科技大学互联网的牛人 电子商务与互联网科技的关系 互联网科技创新创业项目
0