参考:

AsyncTask - 简书
http://www.jianshu.com/p/3b839d7a3fcf

前言

在android应用开发过程中,我们需要是时刻注意保证应用程序的稳定和UI操作响应及时,不稳定或响应不及时会带来不好的用户体验。

为何要引入AsyncTask?

在Android程序开始运行的时候会单独启动一个进程,默认情况下所有这个程序操作都在这个进程中进行。一个Android程序默认情况下只有一个进程,但一个进程中可以有多个线程。

在这些线程中,有一个线程叫做UI线程(也叫Main Thread),除了UI线程外的线程都叫子线程(Worker Thread)。UI线程主要负责控制UI界面的显示、更新、交互等。因此,UI线程中的操作延迟越短越好(流畅)。把一些耗时的操作(网络请求、数据库操作、逻辑计算等)放到单独的线程,可以避免主线程阻塞。

Android给我们提供了一种轻量级的异步任务类AsyncTask。该类中实现异步操作,并提供接口反馈当前异步执行结果及进度,这些接口中有直接运行在主线程中的(如 onPostExecute,onPreExecute等)。

API

 

官方文档

百度翻译:

AsyncTask使适当的和易用的UI线程。这个类可以执行后台操作,并在用户界面上发布结果,而不必处理线程和/或处理程序。

AsyncTask的设计是围绕线程和处理器的一个辅助类,并不构成一个通用的线程框架。asynctasks应该用于短作业(最多。几秒钟)如果你需要保持线程运行很长一段时间,我们强烈建议您使用不同的java.util.concurrent包如执行API提供的,线程池和futuretask。

异步任务被定义为一个在后台线程上运行的运算,其结果是在用户界面上发布的。一个异步任务是由3的泛型类型定义为参数,过程和结果,和4个步骤,称为onpreexecute,doInBackground,onProgressUpdate和onpostexecute。

使用(API)

AsyncTask must be subclassed to be used. The subclass will override at least one method (

doInBackground(Params...)

), and most often will override a second one (

onPostExecute(Result)

.)

AsyncTask必须被子类继承使用。子类至少重写一个方法(doInBackground(Params...)),和最经常会重写第二个方法(onPostExecute(result))

使用案例

调用方式

AsyncTask的泛型

一个异步任务使用的三种类型如下:

1.Params,the type of the parameters sent to the task upon execution.(参数的类型发送到任务执行时。)

网络访问时可以做String来传URI。

2.Progress,the type of the progress units published during the background computation.(后台计算过程中的进度单元类型。)

进度条参数。onProgressUpdate方法可以用这个参数来更新进度条。

3.Result,the type of the result of the background computation.(后台运行的结果类型。)

Result参数可以存储从网络上面获取的数据。

doInBackground将result参数传递给onpostexecute,onpostexecute方法可以用这个参数来更新界面。

Not all types are always used by an asynchronous task. To mark a type as unused, simply use the typeVoid:(不是所有的参数都需要,不用时可以返回void类型)

 

源码:

AsyncTask内部逻辑主要有二部分:

1.与主线程交互,它内部实例化一个静态的自定义类InternalHandler,这个类是继承Handler的,在这个自定义类中绑定了一个叫做AsyncTaskResult的对象,每次子线程需要通知主线程,就调用sendToTarget发消息给handle,然后在handle的handleMessage中AsyncTaskResult根据消息的类型不同(如MESSAGE_POST_PROGRESS会更新进度条,MESSAGE_POST_CANCEL取消任务)而做这些操作都是在UI线程进行的。意味着,从子线程一旦需要和UI线程交互,内部自动调用了handler对象把消息放在主线程。(onProgressUpdate用于更新界面任务进度)

 

 

2.AsyncTask内部调用,虽然可以新建多个AsyncTask的子类实例,但是AsyncTask内部Handler和ThreadPoolExecutor都是static,这么定义是进程范围内共享的,所以AsyncTask控制着的进程范围内所有的子类实例,且该类的所有实例都共用一个线程池(serialExecutor和THREAD_POOL_EXECUTOR)和 另一个线程池Handler(InternalHandler)。

 

 

从代码可以看出,默认核心线程池的大小CORE_POOL_SIZE是根据Runtime.getRuntime().availableProcessors()获取设备的核数(比如你手机双核返回2),通常线程池的大小是默认期望的并发数。如:默认核心线程池大小5。意味着,如果线程池数量小于5,这时候新添加一个异步任务则会新建一个线程,如果数量大于等于5,这时候新建的异步任务会被放入缓存队列中等待。限制APP内AsyncTask并发的线程是有必要的。同时运行任务多,线程多,会导致短时间内手机内存被占完!

事实上,从android 3.0开始,每次新建异步任务的时候AsyncTask内部默认规则是按提交的先后顺序每次只运行一个异步任务。当然你也可以自己指定自己的线程池。

AsyncTask的工作原理

1.从他的execute方法开始分析,会调用executeOnExecutor();其中AsyncTask的onPreExecute方法是最先执行的,然后线程池开始执行。

 

 

同上

2.从代码看,sDefaultExecutor实际上是一个串行的线程池,一个进程中所有的AsyncTask全部都在这个线程池中执行。从SerialExecutor的实现分析AsyncTask的排队执行的过程。

首先系统会把AsyncTask的参数封装为FutureTask对象,FutureTask是一个并发类,在这里它充当了Runnable的作用。

接着这个FutureTask会交给SerialExecutor的execute方法处理,execute方法会先把FutureTask对象插入到任务队列mTask中,如果这时没有正在活动的任务,那么就会调用SeriaExecutor的scheduleNext()类执行下个任务。同一个AsyncTask任务执行完后,AsyncTask会继续执行其他任务知道所有任务都被执行完,从这一点可以看出,默认情况下AsyncTask是串行执行的。

 

同上

3.不行看得想吐了!W~u ~a~a.....

Note:

1.由于Handler需要和主线程交互,而Handler又是内置于AsyncTask中,所有AsyncTask的创建必须在主线程。

2.AsyncTaskResult的doInBackground(Params)方法执行异步任务运行在子线程中,其他方法运行在主线程中,可以操作UI组件。

3.不要手动的去调用AsyncTask的onPreExecute, doInBackground, publishProgress, onProgressUpdate, onPostExecute方法,这些都是由android系统自动调用的。

4.一个AsyncTask任务只能被执行一次。

5.运行中可以随时调用cancel(boolean)方法取消任务,如果成功调用isCancel()会返回true,并不会执行onPostExecute(),取而代之的是调用onCancelled()。从源码看,如果这个任务已经执行了这个时候调用cancel是不会真正的把task结束,而是继续执行,只不过改变的是执行之后的回调方法的onPostExecute还是onCancelled.

 
Note第三点,publishProgress是需要用户手动调用的。onProgressUpdate使用publishProgress方法中的参数。

protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}

sHandler进度消息发送,

case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);

此处处理消息,系统调用重写的onProgressUpdate来更新进度。

AsyncTask2的更多相关文章

  1. 安卓开发--AsyncTask2

    package com.cnn.imageasyncdemo01; import android.app.Activity; import android.content.Intent; import ...

  2. Promise的前世今生和妙用技巧

    浏览器事件模型和回调机制 JavaScript作为单线程运行于浏览器之中,这是每本JavaScript教科书中都会被提到的.同时出于对UI线程操作的安全性考虑,JavaScript和UI线程也处于同一 ...

  3. Android 结合实例学会AsyncTask的用法

    AsyncTask执行时经过四个步骤,执行四个方法: 1.onPreExecute(),运行在UI线程,可以设置或修改UI控件,如显示一个进度条 2.doInBackground,运行在后台线程,不可 ...

  4. Android 结合实例学会AsyncTask的使用方法

    AsyncTask运行时经过四个步骤,运行四个方法:           1.onPreExecute(),执行在UI线程,能够设置或改动UI控件,如显示一个进度条           2.doInB ...

  5. 使用Promise

    Promise所要解决的问题:回调地狱 asyncTask1(data, function (data1){ asyncTask2(data1, function (data2){ asyncTask ...

  6. Spring boot 使用WebAsyncTask处理异步任务

    上文介绍了基于 @Async 注解的 异步调用编程,本文将继续引入 Spring Boot 的 WebAsyncTask 进行更灵活异步任务处理,包括 异步回调,超时处理 和 异常处理. 正文 1. ...

  7. SpringBoot中Async异步方法和定时任务介绍

    1.功能说明 Spring提供了Async注解来实现方法的异步调用. 即当调用Async标识的方法时,调用线程不会等待被调用方法执行完成即返回继续执行以下操作,而被调用的方法则会启动一个独立线程来执行 ...

  8. Android -- AsyncTask 使用和缺陷

    一.AsyncTask的基本用法 由于AsyncTask是一个抽象类,所以如果我们想使用它,就必须要创建一个子类去继承它.在继承时我们可以为AsyncTask类指定三个泛型参数,这三个参数的用途如下: ...

随机推荐

  1. python匿名函数应用--动态计算器

    匿名函数: 一般用于函数体较为简单的运算,和一些不需要函数名的传递.  lambda 参数1:运算举例:  func = lambda x,y:x+y :可以给匿名函数添加变量名. 匿名函数的应用: ...

  2. servlet--获取类路径下资源

     context 获取真实路径(*****) 还可以使用ServletContext对象来获取Web应用下的资源,例如在hello应用的根目录下创建a.txt文件,现在想在Servlet中获取这个资源 ...

  3. Thread -线程的两种创建方式

    package cn.learn.thread.Thread; /* 实现Runnable必须重写run()方法,一般推荐用Runnable实现 */ public class RunnableImp ...

  4. [Linux] 022 RPM 包查询

    1. 查询是否安装 (1) 查询包是否安装 $ rpm -q 包名 选项 释义 -q (query) 查询 (2) 查询所有已安装的 RPM 包 $ rpm -qa 选项 释义 -a (all) 所有 ...

  5. 【洛谷p1025】数的划分

    数的划分[传送门] 算法的话,dfs+剪枝: 据说是01年之前的NOIp提高组: 思路: 这道题是求把n无序的划分成k份的方案数,最直接的搜索方法是依次枚举x1,x2……xk的值,然后判断,显然这么搜 ...

  6. Codeforces 1119D(差分)

    题面 传送门 分析 先考虑\(O(nk)\)的做法,先按s从小到大排序,每个串的数显然形成了n个连续区间\([s_i+l,s_i+r]\),且这些区间的左端点升序排列,然后把区间合并就可以知道有多少个 ...

  7. python------模块和包及异常处理

    一.模块 所有的模块导入都应该尽量往上写,且顺序为: a:内置模块 b:扩展模块 c:自定义模块 #my_module.py print('from the my_module.py') money= ...

  8. k8s常用笔记

    安装docker // 安装docker $ yum install -y docker-ce // 开机启动 && 启动服务 $ systemctl enable docker &a ...

  9. Kvm--03 kvm克隆,桥接网络,热添加

    目录 1.Kvm克隆 1). 完整克隆 2). 链接克隆 2.kvm虚拟机的桥接网络 3.在线热添加网卡,cpu 1). 热添加网卡 2). 热添加内存 3). 热添加cpu参数 1.Kvm克隆 1) ...

  10. 2019西北工业大学程序设计创新实践基地春季选拔赛 D(卢卡斯定理)

    链接:https://ac.nowcoder.com/acm/contest/553/D来源:牛客网 Chino with Equation 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C ...