Android AsyncTask基础知识整理

一、AsyncTask的简介

AsyncTask是一个抽象泛型类,它是由Android封装的轻量级异步类(使用方便、代码简介),它可以在线程中执行后台任务,然后将执行的结果以及进度传递给主线程,并在主线程更新UI。

AsyncTask内部封装了两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler)。

  • SerialExecutor 线程池用于任务的排队,让需要执行的多个耗时任务按顺序排列。
  • THREAD_POOL_EXECUTOR 线程池是真正执行任务的线程池。
  • InternalHandler 用于线程的切换,从工作线程切换到主线程。

二、AsyncTask的泛型参数

public abstract class AsyncTask 
  • Params:开始异步任务时传入的参数类型,在execute()传入,跟doInBackground(Void... params)里的params类型一样。

  • Progress:执行进度,跟onProgressUpdate(Integer... values)的values类型一致,一般情况为Integer。

  • Result:执行结束的返回值,跟doInBackground返回的参数类型一致,并且跟onPostExecute的参数一致。

如果AsyncTask确定不需要传递具体的参数,那么这三个泛型参数可以用Void代替。

三、AsyncTask的核心方法

onPreExecute()

  • 后台任务开始执行之前调用,在主线程调用,用来进行一些界面的初始化操作,如显示一个进度条对话框。

doInBackground(Params...)

  • 这个方法的所有代码都在子线程中执行,我们应该在这里去处理所有的耗时操作。

  • 这个方法不可以进行UI操作,如果需要更新UI,如反馈进度,可以调用publishProgress(Progress...)方法来完成。

onProgressUpdate(Progress...)

  • 当后台任务调用了publishProgress(Progress...)方法后,这个方法就会被调用,方法中携带的参数是后台任务传递过来的。

  • 这个方法可以对UI进行操作,在主线程中进行,可以利用参数的值对界面元素进行相应更新。

onPostExecute(Result)

  • 当doInBackground(Params...)执行完并通过return语句进行返回时,这个方法就会被调用。

  • 返回的数据会作为参数传递到该方法中,可进行一写UI操作,提醒、关闭进度框之类的。

上述方法执行顺序:
onPreExecute() --> doInBackground() --> publishProgress() --> onProgressUpdate() --> onPostExecute()

如果不需要执行更新进度,则:
onPreExecute() --> doInBackground() --> onPostExecute()

AsyncTask还提供了cancel(boolean)方法,用于取消异步任务,在主线程中调用。当cancel(boolean)被调用时,onPostExecute()则不被调用,将会调用onCancelled()方法。但并不是真正的取消任务,只是设置了这个任务为取消状态,我们需要在doInBackground()判断终止任务。

四、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();  
        }  
    }  
}

这里模仿下载任务,doInBackground()执行下载逻辑,onProgressUpdate()显示当前下载进度,onPostExecute()提示任务执行结果。
如果启动任务,只需调用以下代码:

new DownloadTask().execute();  

五、AsyncTask的使用注意事项

  • 异步任务的实例必须在UI线程创建,即AsyncTask对象必须在UI线程创建。

  • execute()、cancelled()方法必须在UI线程调用。

  • 不能在doInBackground()方法中更新UI。

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

六、AsyncTask的缺陷

生命周期:

  • AsyncTask不与任何组件绑定生命周期,所以在Activity或者Fragment创建AsyncTask时,最好在onDestory()调用cancel(boolean)方法。总之我们要确保正确的取消AsyncTask。

内存泄漏:

  • 如果AsyncTask被声明为Activity的非静态内部类,那么AsyncTask会保留一个对创建Activity的引用。如果Activity已经被销毁,AsyncTask还在后台执行,它将继续在内存保留这个引用,导致Activity无法被回收,引起内存泄漏。

cancel(boolean)不一定好使:

  • 当AsyncTask已经完成,亦或其他原因不能被取消,调用cancel(boolean)并没有实际效果,还是会继续执行doInBackground()方法,只是不执行onPostExecute()。
    boolean参数mayInterruptIfRunning决定是否立即stop该Task

结果丢失:

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

串行还是并行:

  • AsyncTask默认串行执行,也可以通过设置executeOnExecutor(Executor)来实现多个AsyncTask并行。

七、AsyncTask与Handler的关系

  • 它们的关系并不大,甚至可以说不是一个层面的东西,因为AsyncTask本质是对Handler的封装,并且内部有自己维护的线程池。

  • 有一些相同的目的,都可以异步执行一些代码,避免阻塞UI线程。

至于AsyncTask的源码理解,等以后理解了,再补上,再次留下了没技术的眼泪~
最后奉上参考博文,毕竟东拼西凑(捂脸):
Android中的线程状态之AsyncTask详解
AsyncTask 使用和缺陷

你可能感兴趣的:(Android AsyncTask基础知识整理)