美文网首页
AsyncTask指南

AsyncTask指南

作者: sunjiandev | 来源:发表于2019-11-07 20:33 被阅读0次

AsyncTask指南

通过AsyncTask,可以正确,轻松地使用UI线程。此类允许您执行后台操作并在UI线程上发布结果,而无需操纵线程和/或处理程序。

AsyncTask被设计为围绕{@link Thread}和{@link Handler}的帮助类,并且不构成通用的线程框架。理想情况下 ,AsyncTasks应该用于短时间的操作(最多几秒钟),一般用于一些io操作,不建议用于网络请求,由于网络请求的不确定性,可能达到十多秒以上。如果需要长时间保持线程运行,强烈建议您使用java.util.concurrent软件包提供的各种API,例如 ExecutorThreadPoolExecutorFutureTask

异步任务是在子线程中执行,并将结果发送到ui线程中。异步任务是由3种一般类型,称为定义ParamsProgressResult,和4个步骤,称为onPreExecutedoInBackgroundonProgressUpdateonPostExecute

用法

必须将AsyncTask子类化才能使用,由于Async是一个抽象类,所以需要子类实现。子类将覆盖至少一个方法 doInBackground,大多数情况下将覆盖第二个方法 onPostExecute

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
      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");
      }
  }

创建完成后,任务将非常简单地执行:

new DownloadFilesTask().execute(url1,url2,url3);

AsyncTask 的三个参数

  • Params 执行时发送给任务的参数的类型
  • Progress,后台计算过程中发布的进度单位的类型。
  • Result,是后台任务计算结果的类型

四个函数

  • onPreExecute(Params): 在任务执行前被调用,一般用于做一些初始化操作。在主线程中执行。
  • doInBackground():该函数在子线程中执行,用于任务的执行过程,比如说 一些io操作的具体逻辑,其结果 可以通过 publishProgress 函数 发生到 onProgressUpdate 函数中。
  • onProgressUpdate(progress):调用 publishProgress 后在UI线程上调用。执行的时间是不确定的。此方法用于在后台任务仍在执行时在界面中显示任何进度。例如,它可用于为进度条设置当前进度或在文本字段中显示日志等。
  • onPostExecute(Result):后台任务执行结束之后会把结果传递到该函数,实在ui 线程中被调用。如果任务被取消了则不会被调用。

取消任务

可以通过调用 cancel(boolean随时取消任务。调用此方法调用此方法不会导致任务立即被取消,只是更改了中断的标志位。控制异步任务执行结束后不会回调onPostExecute()。正确的取消异步任务要cancel()方法doInbacground()做判断跳出循环

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
      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的对象必须在主线程中实例化,execute方法也要在主线程调用(查看3.1节-AsyncTask构造函数)。
  • 同一个AsyncTask任务只能被执行一次,即只能调用一次execute方法,多次调用时将会抛异常(查看3.2里面的第二小节)。
  • cancel()方法无法直接中断子线程,只是更改了中断的标志位。控制异步任务执行结束后不会回调onPostExecute()。正确的取消异步任务要cancel()方法doInbacground()做判断跳出循环。
  • AsyncTask在Activity通常作为匿名的内部类来使用,如果 AsyncTask 中的异步任务在 Activity 退出时还没执行完或者阻塞了,那么这个保持的外部的 Activity 实例得不到释放(内部类保持隐式外部类的实例的引用),最后导致会引起OOM,解决办法是:在 AsyncTask 使用弱引用外部实例,或者保证在 Activity 退出时,所有的 AsyncTask 已执行完成或被取消
  • 会产生阻塞问题,尤其是单任务顺序执行的情况下,一个任务执行时间过长会阻塞其他任务的执行
  • 不建议使用AsyncTask进行网络操作
    AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs。
    Android文档中有写到AsyncTask应该处理几秒钟的操作(通常为轻量的本地IO操作),由于网络操作存在不确定性,可能达到几秒以上,所以不建议使用。

相关文章

网友评论

      本文标题:AsyncTask指南

      本文链接:https://www.haomeiwen.com/subject/oofbbctx.html