Android中AsyncTask详细介绍

AsyncTask是一个很常用的API,尤其异步处理数据并将数据应用到视图的操作场合。其实AsyncTask并不是那么好,甚至有些糟糕。本文我会讲AsyncTask会引起哪些问题,如何修复这些问题,并且关于AsyncTask的一些替代方案。

AsyncTask

从Android API 3(1.5 Cupcake)开始,AsyncTask被引入用来帮助开发者更简单地管理线程。实际上在Android 1.0和1.1也是有类似的实现,那就是UserTask。UserTask和AsyncTask有着相同的API及实现,但是由于由于1.0和1.1的设备份额微乎其微,这里的概念就不会涉及到UserTask。

生命周期

关于AsyncTask存在一个这样广泛的误解,很多人认为一个在Activity中的AsyncTask会随着Activity的销毁而销毁。然后事实并非如此。AsyncTask会一直执行doInBackground()方法直到方法执行结束。一旦上述方法结束,会依据情况进行不同的操作。

1.如果cancel(boolean)调用了,则执行onCancelled(Result)方法
2.如果cancel(boolean)没有调用,则执行onPostExecute(Result)方法

AsyncTask的cancel方法需要一个布尔值的参数,参数名为mayInterruptIfRunning,意思是如果正在执行是否可以打断,如果这个值设置为true,表示这个任务可以被打断,否则,正在执行的程序会继续执行直到完成。如果在doInBackground()方法中有一个循环操作,我们应该在循环中使用isCancelled()来判断,如果返回为true,我们应该避免执行后续无用的循环操作。

总之,我们使用AsyncTask需要确保AsyncTask正确地取消。

不好好工作的cancel()

简而言之的答案,有时候起作用。

如果你调用了AsyncTask的cancel(false),doInBackground()仍然会执行到方法结束,只是不会去调用onPostExecute()方法。但是实际上这是让应用程序执行了没有意义的操作。那么是不是我们调用cancel(true)前面的问题就能解决呢?并非如此。如果mayInterruptIfRunning设置为true,会使任务尽早结束,但是如果的doInBackground()有不可打断的方法会失效,比如这个BitmapFactory.decodeStream() IO操作。但是你可以提前关闭IO流并捕获这样操作抛出的异常。但是这样会使得cancel()方法没有任何意义。

内存泄露

还有一种常见的情况就是,在Activity中使用非静态匿名内部AsyncTask类,由于Java内部类的特点,AsyncTask内部类会持有外部类的隐式引用。详细请参考细话Java:”失效”的private修饰符,由于AsyncTask的生命周期可能比Activity的长,当Activity进行销毁AsyncTask还在执行时,由于AsyncTask持有Activity的引用,导致Activity对象无法回收,进而产生内存泄露。

结果丢失

另一个问题就是在屏幕旋转等造成Activity重新创建时AsyncTask数据丢失的问题。当Activity销毁并创新创建后,还在运行的AsyncTask会持有一个Activity的非法引用即之前的Activity实例。导致onPostExecute()没有任何作用。

串行还是并行

关于AsyncTask时串行还是并行有很多疑问,这很正常,因为它经过多次的修改。如果你并不明白什么时串行还是并行,可以通过接下来的例子了解,假设我们在一个方法体里面有如下两行代码

代码如下:

new AsyncTask1().execute();
new AsyncTask2().execute();

上面的两个任务时同时执行呢,还是AsyncTask1执行结束之后,AsyncTask2才能执行呢?实际上是结果依据API不同而不同。

在1.6(Donut)之前:

在第一版的AsyncTask,任务是串行调度。一个任务执行完成另一个才能执行。由于串行执行任务,使用多个AsyncTask可能会带来有些问题。所以这并不是一个很好的处理异步(尤其是需要将结果作用于UI试图)操作的方法。

从1.6到2.3(Gingerbread)

后来Android团队决定让AsyncTask并行来解决1.6之前引起的问题,这个问题是解决了,新的问题又出现了。很多开发者实际上依赖于顺序执行的行为。于是很多并发的问题蜂拥而至。

3.0(Honeycomb)到现在

好吧,开发者可能并不喜欢让AsyncTask并行,于是Android团队又把AsyncTask改成了串行。当然这一次的修改并没有完全禁止AsyncTask并行。你可以通过设置executeOnExecutor(Executor)来实现多个AsyncTask并行。关于API文档的描述如下

代码如下:

If we want to make sure we have control over the execution, whether it will run serially or parallel, we can check at runtime with this code to make sure it runs parallel:

代码如下:

public static void execute(AsyncTask as) {
  if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR1) {
      as.execute();
  } else {
      as.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  }
}
//(This code does not work for API lvl 1 to 3)

真的需要AsyncTask么

并非如此,使用AsyncTask虽然可以以简短的代码实现异步操作,但是正如本文提到的,你需要让AsyncTask正常工作的话,需要注意很多条条框框。推荐的一种进行异步操作的技术就是使用Loaders。这个方法从Android 3.0 (Honeycomb)开始引入,在android支持包中也有包含。可以通过查看官方的文档来详细了解Loaders

本次译文对原文有少部分删减修改处理。

(0)

相关推荐

  • asynctask的用法详解

    在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行.在单线程模型中始终要记住两条法则: 1. 不要阻塞UI线程 2. 确保只在UI线程中访问Android UI工具包 当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理.所以主线程通常又被叫做UI线程.

  • android教程之使用asynctask在后台运行耗时任务

    , Android中实现了默认的进度提示对话框,即ProgressDialog,通过实例化和一些简单设置,就可以使用了. 复制代码 代码如下: private class DownloadDBTask extends AsyncTask<String, Integer, String> {           // 可变长的输入参数,与AsyncTask.exucute()对应           ProgressDialog pdialog;           public Downloa

  • 详解Android中AsyncTask机制

    在Android当中,提供了两种方式来解决线程直接的通信问题,一种是通过Handler的机制,还有一种就是今天要详细讲解的 AsyncTask 机制. AsyncTask       AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程. 怎么来理解AsyncTask呢?通俗一点来说,AsyncTask就相当于Android给我们提供了一个多线

  • Android中AsyncTask的用法实例分享

    *  AsyncTask 看上去修改后的connect()方法已经可用了,但是这种匿名线程的方式是存在缺陷的:第一,线程的开销较大,如果每个任务都要创建一个线程,那么应用 程序的效率要低很多:第二,线程无法管理,匿名线程创建并启动后就不受程序的控制了,如果有很多个请求发送,那么就会启动非常多的线程,系统将不堪重负. 另外,前面已经看到,在新线程中更新UI还必须要引入handler,这让代码看上去非常臃肿. 为了解决这一问题,OPhone在1.5版本引入了AsyncTask.AsyncTask的特

  • Android开发笔记之:AsyncTask的应用详解

    AsyncTask的介绍及基本使用方法关于AsyncTask的介绍和基本使用方法可以参考官方文档和<Android开发笔记之:深入理解多线程AsyncTask>这里就不重复.AsyncTask引发的一个问题上周遇到了一个极其诡异的问题,一个小功能从网络上下载一个图片,然后放到ImageView中,是用AsyncTask来实现的,本身逻辑也很简单,仅是在doInBackground中用HTTP请求把图片的输入流取出,然后用BitmapFactory去解析,然后再把得到的Bitmap放到Image

  • Android开发笔记之:深入理解多线程AsyncTask

    Understanding AsyncTaskAsyncTask是Android 1.5 Cubake加入的用于实现异步操作的一个类,在此之前只能用Java SE库中的Thread来实现多线程异步,AsyncTask是Android平台自己的异步工具,融入了Android平台的特性,让异步操作更加的安全,方便和实用.实质上它也是对Java SE库中Thread的一个封装,加上了平台相关的特性,所以对于所有的多线程异步都强烈推荐使用AsyncTask,因为它考虑,也融入了Android平台的特性,

  • AsyncTask官方文档教程整理

    简介 Android给我们提供了一种轻量级的异步任务类AsyncTask.该类中实现异步操作,并提供接口反馈当前异步执行结果及进度,这些接口中有直接运行在主线程中的(如 onPostExecute,onPreExecute等). AsyncTask可以轻松正确的使用UI线程,这个类允许你在后台操作,并且不需要使用threads或者handler将结果发布到UI线程. AsyncTask设计之初就是辅助Thread和Handler的,并且不会生成线程.AsyncTask应该被用于短时间内的操作(最

  • Android中AsyncTask详细介绍

    AsyncTask是一个很常用的API,尤其异步处理数据并将数据应用到视图的操作场合.其实AsyncTask并不是那么好,甚至有些糟糕.本文我会讲AsyncTask会引起哪些问题,如何修复这些问题,并且关于AsyncTask的一些替代方案. AsyncTask 从Android API 3(1.5 Cupcake)开始,AsyncTask被引入用来帮助开发者更简单地管理线程.实际上在Android 1.0和1.1也是有类似的实现,那就是UserTask.UserTask和AsyncTask有着相

  • Android中AsyncTask异步任务使用详细实例(一)

    AsyncTask是Android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程. 使用AsyncTask最少要重写以下两个方法: 1.doInBackground(Params-) 后台执行,比较耗时的操作都可以放在这里.注意这里不能直接操作UI.此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间.在执行过程中可以调用publicProgress(Progres

  • 浅谈Android中AsyncTask的工作原理

    概述 实际上,AsyncTask内部是封装了Thread和Handler.虽然AsyncTask很方便的执行后台任务,以及在主线程上更新UI,但是,AsyncTask并不合适进行特别耗时的后台操作,对于特别耗时的任务,个人还是建议使用线程池.好了,话不多说了,我们先看看AsyncTask的简单用法吧. AsyncTask使用方法 AsyncTask是一个抽象的泛型类.简单的介绍一下它的使用方式代码如下: package com.example.huangjialin.myapplication;

  • CentOS Linux系统搭建Android开发环境详细介绍

    CentOS Linux系统搭建Android开发环境详细介绍 很多人都是在Windows下进行Android开发,但是对于Linux,Android开发环境方面的资料比较少,今天在网上找到了一位网友分享的在CentOS Linux系统中搭建Android开发环境的过程.下面就是其介绍的配置的详细步骤原文: 由于我最近每天使用的是CentOS 5.5,所以选择CentOS5.5作为我的开发环境. 主要包括以下步骤: 1.JDK安装 2.Eclipse安装 3.ADT安装 4.Android SD

  • 详解Android 中AsyncTask 的使用

    详解Android 中AsyncTask 的使用 1.首先我们来看看AsyncTask 的介绍:   Handler 和 AsyncTask 都是android 中用来实现异步任务处理的方式:其中: Handler 实例向 UI 线程发送消息,完成界面更新, 优点:对整个过程控制的比较精细:         缺点:代码相对臃肿,多个任务同时执行时,不易对线程进行精确的控制: AsyncTask :比Handler 更轻量级一些,适用于简单的异步处理: 优点:简单 | 快捷 | 过程可控:    

  • Android中AsyncTask与handler用法实例分析

    本文实例讲述了Android中AsyncTask与handler用法.分享给大家供大家参考,具体如下: 首先,我们得明确下一个概念,什么是UI线程.顾名思义,ui线程就是管理着用户界面的那个线程! android的ui线程操作并不是安全的,并且和用户直接进行界面交互的操作都必须在ui线程中进行才可以.这种模式叫做单线程模式. 我们在单线程模式下编程一定要注意:不要阻塞ui线程.确保只在ui线程中访问ui组件 当我们要执行一个复杂耗时的算法并且最终要将计算结果反映到ui上时,我们会发现,我们根本没

  • Android自定义控件属性详细介绍

     Android自定义控件属性详细介绍 1. reference:参考某一资源ID.  (1)属性定义: <declare-styleable name = "名称"> <attr name = "background" format = "reference" /> </declare-styleable> (2)属性使用: <ImageView android:layout_width = "

  • python中进程间通信详细介绍

    目录 进程间通信(IPC) 管道通信(Pipe) 1.通信原理 2. 实现方法 共享内存 1.通信原理 2.实现方法 信号量(信号灯集) 1.通信原理 2. 实现方法 3.代码演示 进程间通信(IPC) 必要性 进程间空间独立,资源不共享,此时在需要进程间数据传输时就需要特定的手段进行数据通信 常用进程间通信方法 管道 消息队列 共享内存 型号 信号量 套接字 管道通信(Pipe) 1.通信原理 在内存中开辟管道空间,生成管道操作对象,多个进程使用同一个管道对象进行读写即可实现通信 代码演示(w

  • Linux系统中日志详细介绍

    目录 1.日志相关服务 2.系统中常见的日志文件 1.日志相关服务 在CentOS 6.x中日志服务已经由rsyslogd取代了原先的syslogd服务.RedHat认为syslogd已经不能满足在工作中的需求,rsyslogd服务支持的功能更加丰富. rsyslogd服务相比syslogd服务具有一些新的特点: 基于TCP网络协议传输日志信息. 更安全的网络传输方式. 有日志消息的及时分析框架. 后台数据库.配置文件中可以写简单的逻辑判断. 与syslog配置文件相兼容. 2.系统中常见的日志

  • MySQL 中字符集详细介绍

    目录 MySQL 中的 UTF8 修改MySQL数据库的编码 字符集的比较规则 MySQL查询时区分大小写 MySQL 中的 UTF8 在 MySQL 中, utf8 编码格式有点特殊, 它不是我们通常用到的 utf8, 而是 utf8mb3 编码的缩写. 而 utf8mb4 才是我们常说的那个 utf8. utf8mb3:阉割过的 utf8 字符集, 只使用 1-3 个字节表示字符. utf8mb4:正宗的 utf8 字符集, 使用 1-4 个字节表示字符. 通常情况下, utf8mb3 和

随机推荐