AsyncTask面试详解

这篇文章用来记录Android提供的轻量级异步类AsyncTask,文章分为一下几个章节:

  1. 什么是AsyncTask
  2. AsyncTask的使用方式
  3. AsyncTask的内部原理
  4. AsyncTask的注意事项

什么是AsyncTask?

AsyncTask是Android提供的轻量级的异步任务类,它本质上是是一个封装了Handle和线程池的异步框架。通过AsyncTask可以更加方便的执行后台任务以及更新UI。

但是,AsyncTask并不适合执行特别耗时的操作,特别耗时的操作建议使用线程池

AsyncTask的内部封装了两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler)。其中SerialExecutor线程池用于任务的排队,让需要执行的多个耗时任务,按顺序排列,THREAD_POOL_EXECUTOR线程池才真正地执行任务,InternalHandler用于从工作线程切换到主线程。


AsyncTask的使用方式
AsyncTask的使用方式就涉及到三个参数,五个方法

1.三个参数
AsyncTask的类声明如下:

public abstract class AsyncTask

AsyncTask是一个泛型抽象类,有三个泛型参数,三个泛型类型参数的含义如下:
Params: 开始异步任务执行时传入的参数类型;
Progress:异步任务执行过程中,返回进度值的类型;
Result: 异步任务执行完成后,返回的结果类型;
如果AsyncTask确定不需要传递具体参数,那么这三个泛型参数可以用Void来代替。

2.五个AsyncTask的核心方法:
onPreExecute():该方法在主线程中执行,在异步任务执行之前调用,一般用于做一些初始化操作,准备工作(如展示一个进度条等);

doInBackground(Params…):在线程池中执行,此方法用于执行异步任务,其结果返回给onPostExecute(Result)方法。在此方法中调用publishProgress(),会调用onProgressUpdate(Progress…);

onProgressUpdate(Progress…): 在主线程中执行,当任务进度发生变化时该方法被调用,

onPostExecute(Result):主线程中执行,result是doInBackground(Params…)的返回值;

onCancelled();同样在主线程中执行,当异步任务被取消时,onCancelled()会被调用,这时,onPostExecute不会被调用;

AsyncTask的简单使用

class DownloadTask extends AsyncTask {  

    @Override  
    protected void onPreExecute() {  
        progressDialog.show();  
    }  

    @Override  
    protected Boolean doInBackground(Void... params) {  
        try {  
            while (true) {  
                int downloadPercent = doDownload();  
                publishProgress(downloadPercent);  
                if (downloadPercent >= 100) {  
                    break;  
                }  
            }  
        } catch (Exception e) {  
            return false;  
        }  
        return true;  
    }  

    @Override  
    protected void onProgressUpdate(Integer... values) {  
        progressDialog.setMessage("当前下载进度:" + values[0] + "%");  
    }  

    @Override  
    protected void onPostExecute(Boolean result) {  
        progressDialog.dismiss();  
        if (result) {  
            Toast.makeText(context, "下载成功", Toast.LENGTH_SHORT).show();  
        } else {  
            Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show();  
        }  
    }  
}

接着调用new DownloadTask().execute();开启该异步任务。

上述代码比较简单,在doInBackground中执行下载任务,结果返回给onPostExecute来提示任务的执行结果。


③AsyncTask的内部原理
这里就不深入源码来进行解析了,本人水平不够,只根据《Android开发艺术探索》走了一遍,建议大家也可以更仔细的研读。

AsyncTask的内部封装了两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler)。其中SerialExecutor线程池用于任务的排队,让需要执行的多个耗时任务,按顺序排列,THREAD_POOL_EXECUTOR线程池才真正地执行任务,InternalHandler用于从工作线程切换到主线程。

内部原理:
一:AsyncTask本质上是一个静态的线程池,它的派生子类 可以实现不同的异步任务,这些异步任务都提交到静态的线程中执行。
二:线程池中的工作线程执行doInBackground()方法来执行异步任务
三:当任务状态改变之后,工作线程会向主线程发送消息,AsyncTask内部的InternalHandler相应这些消息,并调用关的函数。


④AsyncTask的注意事项
1.异步任务的实例必须在UI线程中创建,即AsyncTask对象必须在UI线程中创建。

2.execute(Params… params)方法必须在UI线程中调用。

3.不要手动调用onPreExecute(),doInBackground(Params… params),onProgressUpdate(Progress… values),onPostExecute(Result result)这几个方法。

5.不能在doInBackground(Params… params)中更改UI组件的信息。

6.一个任务实例只能执行一次,如果执行第二次将会抛出异常。

AsyncTask使用不当的后果:
1.内存泄漏
如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会持有Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄露。

解决办法:将AsyncTask设为静态的;也可在静态Async内部持有外部Activity的弱引用去;可以在外部Activity的onDestory方法中即使取消AsyncTask。

2.生命周期
AsyncTask不与任何组件绑定生命周期,所以在Activity/或者Fragment中创建执行AsyncTask时,最好在Activity/Fragment的onDestory()调用 cancel(boolean);

3.结果丢失
屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask(非静态的内部类)会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。

4.并行 or 串行
现在AsyncTask内部的任务是串行执行的,我们可以调用executeOnExector()来让任务并行执行。O

以上内容总结自《Android开发艺术探索》,以及博客,慕课网实战课程。

你可能感兴趣的:(AsyncTask,Android基础)