安卓开发面试题(10/30)AsyncTask全解析

牛客高级系列专栏:

安卓(安卓系统开发也要掌握)


嵌入式


本人是2020年毕业于广东工业大学研究生:许乔丹,有国内大厂CVTE和世界500强企业安卓开发经验,该专栏整理本人对常见安卓高频开发面试题的理解;

网上安卓资料千千万,笔者将继续维护专栏,一杯奶茶价格不止提供答案解析,承诺提供专栏内容免费技术答疑,直接咨询即可。助您提高安卓面试准备效率,为您面试保驾护航!

正文开始⬇

AsyncTask在实际开发过程中偶尔会用到,因此也是面试官喜欢问的模块,不过个人觉得被提问的概率属于中等。面试官可能会问:

  1. AsyncTask是什么?能解决什么问题 ⭐⭐⭐⭐
  2. 给我谈谈AsyncTask的三个泛型参数作用以及它的一些方法作用。⭐⭐⭐
  3. 给我说说AsyncTask的原理。⭐⭐⭐
  4. 你觉得AsyncTask有不足之处吗?有何使用注意事项?⭐⭐⭐

看完以下的解析,一定可以让面试官眼前一亮。

目录

  • 1、AsyncTask介绍
    • 1.1 AsyncTask的使用
    • 1.2 核心方法
    • 1.3 三个泛型类参数
  • 2、AsyncTask使用心得
    • 2.1 AsyncTask的使用注意事项
    • 2.2 AsyncTask的不足之处
  • 3、源码分析(进阶)
  • 4、总结

1、AsyncTask介绍

回顾上一节的问题:更新UI的方式有哪些?答案有:

  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable),View.postDelay(Runnable, long)
  • Handler
  • AsyncTask
  • Rxjava
  • LiveData

本文的主角AsyncTask,本人现在用得比较少,更多用的是Rxjava。同时面试的时候知道AsyncTask是什么?怎么用?有什么不足之处或者需要注意什么?懂了这三个问题一般就可以了。至于看源码,可当作进阶,个人建议还是有必要学习一下的。那么AssyncTask究竟是什么呢?

AsyncTask是一个轻量级的异步任务类,可以在线程池里执行比较耗时的后台任务,然后把执行的进度和最后的结果传递给主进程,并在主进程中更新UI。使用容易,而且好理解。

1.1 AsyncTask的使用

同样从使用入手,看看代码。以下代码以往文件里写数据为例:

private class FileTestTask extends AsyncTask<Void, Long, Boolean> { //1

    @Override
    protected void onPreExecute() {
        //初始化一些数据
        initProcessInfo();
    }

    @Override
    protected Long doInBackground(Void... integers) {
        //创建目录
        ...
        while (mTotalWriteSize <= mInitFreeDataValue) {
            ...
            mTotalWriteSize += writeSize / 1024 / 1024; // M
            //2:反馈当前任务进度
            publishProgress(mTotalWriteSize);
        }

        return true;
    }

    @Override
    protected void onProgressUpdate(Long... progresses) { //3
        if (progresses != null && progresses.length >= 1) {
            updateProcessInfo(progresses[0]); //更新进度条
        }
    }

    @Override
    protected void onPostExecute(Boolean result) { //4
        if (result) {
            updateContentInfo(R.string.text_show_result_test_over);
        } else {
            updateContentInfo(R.string.text_show_result_fail);
        }
    }
}

//主线程中使用自定义的FileTestTask
if (mFileTestTask == null) {
    mFileTestTask = new FileTestTask();
    mFileTestTask.execute();
}

1.2 核心方法

  • onPreExecute():字面上就是“提前执行”,会在后台任务开始前调用,并在主线程中执行,因此常用于初始化一些数据和界面。
  • doInBackground(Params...):字面上是“在背后处理”,就是在后台处理所有耗时的任务,这些任务都会在子线程中处理。有两个需要注意的点:
    • 不能在这个函数进行UI操作,因为该函数是在子线程运行的。如果需要更新当前任务完成进度条,需要运行publishProgress(Progress...),如上面的注释2,而最终是调用onProgressUpdate()去更新进度条;
    • 执行完之后可以通过return将执行的结果返回,返回的结果会在onPostExecute()里执行,如注释4,我这边只是更新了一个文字内容。
  • onProgressUpdate(Progress...):如上一段所述,调用publishProgress(Progress...)后会把参数(如当前任务处理的进度)传递给onProgressUpdate()并被调用,因为该方法在主进程进行,因此可以进行UI修改。
  • onPostExecute():如上所述,doInBackground()会把执行结果返回给 onPostExecute()并被调用,该方法也在主线程运行,可以做一些结尾的动作,如提示任务完成等。

上面几个核心方法的调用顺序为: onPreExecute() --> doInBackground() --> publishProgress() --> onProgressUpdate() --> onPostExecute()。

如果不需要更新进度则为onPreExecute() --> doInBackground() --> onPostExecute()。

1.3 三个泛型类参数

在1.1小节案例代码里的注释1 可以看到AsyncTask<Void, Long, Boolean>,其原型是 AsyncTask<Params, Progress, Result>,这三个泛型类参数含义如下:

  • Params:开始异步任务执行时传入的参数类型,对应doInBackground(),本案例是Void,代表不需要传入参数;

  • Progress:异步任务执行过程中,返回下载进度值的类型,对应onProgressUpdate(),本案例是Long,代表目前已经写入的字节数;

  • Result:异步任务执行完成后,返回的结果类型,对应onPostExecute(),本案例返回的是Boolean类型,true代表任务完成;

2、AsyncTask使用心得

2.1 AsyncTask的使用注意事项

从第1小节,我们了解了AsyncTask的使用方法和步骤,现在再强调几个注意点,不仅面试官可能会问到,平时自己工作中也要多注意:

  • AsyncTask的实例需要在UI线程也就是主线程中创建,调用execute()开始执行任务时,也要在主线程执行;
  • 不要手动调用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)这几个方法;
  • 只有onPreExecute(),onProgressUpdate(Progress... values),onPostExecute(Result result)可以执行UI相关操作,doInBackground(Params... params)不能更改UI界面;
  • 一个任务实例只能执行一次execute(),执行多次会报异常。

2.2 AsyncTask的不足之处

  1. 生命周期

AsyncTask不与任何组件绑定生命周期,因此会出现组件生命周期结束了,但AsyncTask还存在,所以需要在onDestroy()调用 cancel(boolean),手动结束AsyncTask;

  1. 内存泄漏

和之前说的Handler造成内存泄露的原因是一样的。如果AsyncTask被声明为Activity的非静态的内部类,如本文使用代码案例一样,那么AsyncTask会保留一个所在Activity的引用。如果Activiy被销毁,此时因此AsyncTask保留了它的引用,导致Activity无法被回收,引起内存泄露。

3.) 结果丢失

如果屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity重新创建,如果之前运行的AsyncTask是非静态的内部类,此时就会持有之前旧的Activity的引用,而旧的Activity已经销毁了,这时调用onPostExecute()再去更新界面将不再生效,无法更新到新的Activity到界面。

3、 源码分析(进阶)

如果看完前面2节,去面试已经没问题了,对AsyncTask的源码分析属于进阶,如果有时间,建议看看源码,因为整个第3节的源码代码关联性很强,为了方便说明,所有代码块的关键代码行的注释码都是连贯的。

回顾下AsyncTak的使用方法

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Android高频面试题全解析 文章被收录于专栏

#提供免费售后答疑!!花一杯奶茶的钱获得安卓面试答疑服务,稳赚不赔# Android发展已经很多年,安卓资料网上千千万,本专栏免费提供专栏内容技术答疑!!私聊当天必回。在阅读过程或者其他安卓学习过程有疑问,都非常欢迎私聊交流。

全部评论
收藏收藏~
点赞 回复 分享
发布于 2022-12-13 21:27 广西

相关推荐

09-29 17:44
已编辑
蔚来_测(准入职员工)
//鲨鱼辣椒:见不了了我实习了四个月上周再投筛选了一天就给我挂了
点赞 评论 收藏
分享
7 10 评论
分享
牛客网
牛客企业服务