安卓开发面试题(10/30)AsyncTask全解析
牛客高级系列专栏:
安卓(安卓系统开发也要掌握)
- 想通关安卓面试,请看(承诺免费售后答疑):《150道安卓高频面试题目录及答案链接》
- 想通关安卓系统面试,请看:《140道安卓系统Framework面试题目录及答案链接》
- 想进阶安卓开发,请看(承诺免费售后答疑):《Android进阶知识体系解析_15大安卓进阶必备知识点》
- 想了解安卓APP完整开发流程,请看(承诺免费售后答疑):《安卓APP完整开发流程》
- 想掌握安卓App性能优化,请看(承诺免费售后答疑):《安卓性能优化讲解和实战专栏》
- 想掌握Gradle语法和配置,制作Gradle插件,请看(承诺免费售后答疑):《安卓Gradle语法解析和实践大全》
嵌入式
- 想通关嵌入式面试,请看: 《111道嵌入式面试题目录及答案链接》
- 想多掌握几个嵌入式项目,请看:《6个嵌入式项目交流分享(附源码)》
本人是2020年毕业于广东工业大学研究生:许乔丹,有国内大厂CVTE和世界500强企业安卓开发经验,该专栏整理本人对常见安卓高频开发面试题的理解;
网上安卓资料千千万,笔者将继续维护专栏,一杯奶茶价格不止提供答案解析,承诺提供专栏内容免费技术答疑,直接咨询即可。助您提高安卓面试准备效率,为您面试保驾护航!
正文开始⬇
AsyncTask在实际开发过程中偶尔会用到,因此也是面试官喜欢问的模块,不过个人觉得被提问的概率属于中等。面试官可能会问:
- AsyncTask是什么?能解决什么问题 ⭐⭐⭐⭐
- 给我谈谈AsyncTask的三个泛型参数作用以及它的一些方法作用。⭐⭐⭐
- 给我说说AsyncTask的原理。⭐⭐⭐
- 你觉得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的不足之处
- 生命周期
AsyncTask不与任何组件绑定生命周期,因此会出现组件生命周期结束了,但AsyncTask还存在,所以需要在onDestroy()调用 cancel(boolean),手动结束AsyncTask;
- 内存泄漏
和之前说的Handler造成内存泄露的原因是一样的。如果AsyncTask被声明为Activity的非静态的内部类,如本文使用代码案例一样,那么AsyncTask会保留一个所在Activity的引用。如果Activiy被销毁,此时因此AsyncTask保留了它的引用,导致Activity无法被回收,引起内存泄露。
3.) 结果丢失
如果屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity重新创建,如果之前运行的AsyncTask是非静态的内部类,此时就会持有之前旧的Activity的引用,而旧的Activity已经销毁了,这时调用onPostExecute()再去更新界面将不再生效,无法更新到新的Activity到界面。
3、 源码分析(进阶)
如果看完前面2节,去面试已经没问题了,对AsyncTask的源码分析属于进阶,如果有时间,建议看看源码,因为整个第3节的源码代码关联性很强,为了方便说明,所有代码块的关键代码行的注释码都是连贯的。
回顾下AsyncTak的使用方法
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
#提供免费售后答疑!!花一杯奶茶的钱获得安卓面试答疑服务,稳赚不赔# Android发展已经很多年,安卓资料网上千千万,本专栏免费提供专栏内容技术答疑!!私聊当天必回。在阅读过程或者其他安卓学习过程有疑问,都非常欢迎私聊交流。