iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >Android AsyncTask的优缺点详解
  • 542
分享到

Android AsyncTask的优缺点详解

asynctaskAndroid 2022-06-06 04:06:28 542人浏览 安东尼
摘要

1、Asynctask简介 1.1 使用方法简介 Asynctask作为Android的基础之一,怎么使用就不多讲解了,网上到处都是教程,建议查看Android官方api文档:

1、Asynctask简介

1.1 使用方法简介

Asynctask作为Android的基础之一,怎么使用就不多讲解了,网上到处都是教程,建议查看Android官方api文档:https://developer.android.Google.cn/reference/android/os/AsyncTask.html

这里只实现一个小Demo程序,供大家赏玩:

界面:

这个程序其实特别简单,就是两个按钮,点击分别用来测试AysncTask和Handler两种模式的实现,点击后会有相应的Log提示。

功能简介:

Asynctask的实现:


private class IAsyncTask extends AsyncTask<String, Integer, String> {
 protected String doInBackground(String... args1) {
 Log.i(TAG, "doInBackground in:" + args1[0]);
 int times = 10;
 for (int i = 0; i < times; i++) {
 publishProgress(i);//提交之后,会执行onProcessUpdate方法
 }
 Log.i(TAG, "doInBackground out");
 return "over";
 }
 
 protected void onCancelled() {
 Log.i(TAG, "onCancelled");
 }
 
 protected void onPostExecute(String args3) {
 Log.i(TAG, "onPostExecute:" + args3);
 }
 
 @Override
 protected void onPreExecute() {
 Log.i(TAG, "onPreExecute");
 }
 
 @Override
 protected void onProgressUpdate(Integer... args2) {
 Log.i(TAG, "onProgressUpdate:" + args2[0]);
 }
 }

点击第一个按钮后会执行这里,点击按钮的写法如下:


mBtnSyncTask.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 new IAsyncTask().execute("yanlog test");
 }
 });

执行结果的Log如下:


02-19 21:55:12.179 10824-11010/com.plbear.asynctasktest I/AsyncTaskTest: doInBackground in:yanlog test//doInbackground是在10824进程,11010线程中执行
02-19 21:55:12.179 10824-11010/com.plbear.asynctasktest I/AsyncTaskTest: doInBackground out 
02-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:0//剩下的都是在10824线程中执行,Android特别好的是,主线程的线程号跟进程号是一致的
02-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:1
02-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:2
02-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:3
02-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:4
02-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:5
02-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:6
02-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:7
02-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:8
02-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:9
02-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onPostExecute:over

Handler+Message实现:

 主要代码如下:


 private class IHandler extends Handler{
 @Override
 public void handleMessage(Message msg){
 switch(msg.what){
 case 1:
  Log.e(TAG,"handler:"+msg.obj);
  break;
 default:
  break;
 }
 }
 }

其中,调用地方如下:


mBtnHandlerTest.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 final Handler handler = new IHandler();
 new Thread(new Runnable() {
  @Override
  public void run() {
  for (int i = 0; i < 10; i++) {
  Message msg = new Message();
  msg.what = 1;
  msg.obj = new Integer(i);
  Log.e(TAG, "post message:" + i);
  handler.sendMessage(msg);
  }
  }
 }).start();
 }
 });

可以看到Log打印结果如下:


02-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:0 //可以看到提交是在9319号子进程中提交
02-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:1
02-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:2
02-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:3
02-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:4
02-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:5
02-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:6
02-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:7
02-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:8
02-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:9
02-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:0 //可以看到提交完是在9234主线程中执行。
02-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:1
02-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:2
02-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:3
02-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:4
02-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:5
02-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:6
02-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:7
02-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:8
02-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:9

以上,简单梳理了下怎么实现,不赘言。

1.2 Android 内部源码实现

关于Handler+Message+Message Queue+Looper的实现就不介绍了,老生常谈了。所以下面主要看一下AsyncTask的源码实现:

AsyncTask的核心方法应该是

public final AsyncTask<Params, Progress, Result> execute(Params... params)

那我们就看下当调用了execute方法后,都发生了什么,下面是执行的序列图。

我知道我画的不够标准了,凑合着看吧。下面关于这个图的一些说明。

在第4步,execute的时候,这个时候可以看到,doInBackground已经转到子线程中执行了,这个是很关键的一个点,我特意用了一个异步处理的箭头标注了。 在第9步,当doInbackground执行完,执行到finish方法的时候,由通过sendMessage的方法回到了主线程中了,所以后面的onPostExecute和onCanceled都是在主线程中执行的。

嗯,就这么多吧。关于AsyncTask的源码我上传到GitHub中了,大家对照着源码看会更清楚一点。

Https://github.com/YanYoJun/AndroidSource/blob/master/AsyncTask.java

关于AsyncTask的源码分析,还有一篇博客写的很好,请参看:

//www.jb51.net/article/81939.htm

备注:

源码里面还有三个地方值得深究下,分别是:

FutureTask值得看下,回头写了博客我把链接贴在这里 AsyncTask中的SerialExecutor类写的太漂亮了,回头单独写一个博客欣赏下。 关于上面的ThreadPollExecutor我其实没有研究。。。回头写个博客研究下。

2、优点

简单,快捷

这个说法就是近乎于扯淡吧,主要还是看使用习惯,我就挺喜欢用Handler的。

但是Android定义了这个东西,可以看到各种消息封装的还是很不错的,很规范。大家可以按照这个“优美的框架”来写,代码不会太出格。

3、缺点

3.1  AsyncTask实际上后台线程之后一个!!!

今天仔细研究了下源码,发现网上写的大部分是错的,AsyncTask的真正的后台线程只有一个!!不信,看下面的代码:

我们首先定义一个IAsyncTAsk,其中的doInBackground方法这么写:


private class IAsyncTask extends AsyncTask<String, Integer, String> {
 protected String doInBackground(String... args1) {

 Log.i(TAG, "doInBackground in thread:" + args1[0]);
 try {
 int times = 4;
 for (int i = 0; i < times; i++) {
  Log.i(TAG, "thread alive:" + i + " for times"+args1[0]); //这个doInBackground就打印一个Log,然后sleep 20 毫秒
  Thread.sleep(20);
 }
 } catch (Exception e) {
 }
 return "over";
 }

调用的地方这么写:


 int N = 5;
 for (int i = 0; i < N; i++) {
  Log.d(TAG,"asyncTask post Task:"+i);
  new IAsyncTask().execute("asyncTask times:"+i); //点击Button后,在onClick方法中建立5个后台子线程。
 }

我们来看打印结果:


02-20 21:48:08.206 14812-14812/com.plbear.asynctasktest D/AsyncTaskTest: asyncTask post Task:0 //在主线程中进行提交操作
02-20 21:48:08.211 14812-14812/com.plbear.asynctasktest D/AsyncTaskTest: asyncTask post Task:1
02-20 21:48:08.211 14812-14812/com.plbear.asynctasktest D/AsyncTaskTest: asyncTask post Task:2
02-20 21:48:08.211 14812-14812/com.plbear.asynctasktest D/AsyncTaskTest: asyncTask post Task:3
02-20 21:48:08.211 14812-14812/com.plbear.asynctasktest D/AsyncTaskTest: asyncTask post Task:4
02-20 21:48:08.212 14812-18067/com.plbear.asynctasktest I/AsyncTaskTest: doInBackground in thread:asyncTask times:0 //可以看到,虽然系统开起了18067、18068、
02-20 21:48:08.212 14812-18067/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:0 for timesasyncTask times:0//18069,18070这几个子线程,但是这几个子线程
02-20 21:48:08.232 14812-18067/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:1 for timesasyncTask times:0 //是串行执行的!!!震惊了有没有!!!
02-20 21:48:08.253 14812-18067/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:2 for timesasyncTask times:0 //这不是巧合,试了好几次都是这样!!
02-20 21:48:08.273 14812-18067/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:3 for timesasyncTask times:0
02-20 21:48:08.294 14812-18068/com.plbear.asynctasktest I/AsyncTaskTest: doInBackground in thread:asyncTask times:1
02-20 21:48:08.294 14812-18068/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:0 for timesasyncTask times:1
02-20 21:48:08.315 14812-18068/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:1 for timesasyncTask times:1
02-20 21:48:08.335 14812-18068/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:2 for timesasyncTask times:1
02-20 21:48:08.356 14812-18068/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:3 for timesasyncTask times:1
02-20 21:48:08.377 14812-18069/com.plbear.asynctasktest I/AsyncTaskTest: doInBackground in thread:asyncTask times:2
02-20 21:48:08.377 14812-18069/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:0 for timesasyncTask times:2
02-20 21:48:08.397 14812-18069/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:1 for timesasyncTask times:2
02-20 21:48:08.417 14812-18069/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:2 for timesasyncTask times:2
02-20 21:48:08.438 14812-18069/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:3 for timesasyncTask times:2
02-20 21:48:08.462 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: doInBackground in thread:asyncTask times:3
02-20 21:48:08.462 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:0 for timesasyncTask times:3
02-20 21:48:08.483 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:1 for timesasyncTask times:3
02-20 21:48:08.504 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:2 for timesasyncTask times:3
02-20 21:48:08.524 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:3 for timesasyncTask times:3
02-20 21:48:08.545 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: doInBackground in thread:asyncTask times:4
02-20 21:48:08.545 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:0 for timesasyncTask times:4
02-20 21:48:08.565 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:1 for timesasyncTask times:4
02-20 21:48:08.585 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:2 for timesasyncTask times:4
02-20 21:48:08.606 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:3 for timesasyncTask times:4

你本来希望系统应该这么执行

但是实际上系统是这么执行的:

那么从源码看下为啥会这样吧。

AsyncTask中默认的Exector是这个private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;看下SERIAL_EXECUTOR是这么定义的


public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); //这是一个串行处理的Executor
.........................
 private static class SerialExecutor implements Executor {
 final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
 Runnable Mactive;
 public synchronized void execute(final Runnable r) {
 mTasks.offer(new Runnable() { //先把要执行的子线程统一丢到mTasks队列中,这其中封装一遍Runnable
 public void run() {
  try {
  r.run();
  } finally {
  scheduleNext(); //当前面一个子线程处理完,开始处理下一个
  }
 }
 });
 if (mActive == null) {
 scheduleNext();
 }
 }
 protected synchronized void scheduleNext() { //依次从队列中取下一个元素,串行执行
 if ((mActive = mTasks.poll()) != null) {
 THREAD_POOL_EXECUTOR.execute(mActive); 
 }
 }
 }

呵呵,这下子明白了吧。

Google为什么要怎么实现我不得而知,估计有什么我没有明白的好处在里面吧。那么有没有办法规避呢?

可以看到上面有一个THREAD_POOL_EXECUTOR,这个也是一个executor是这么定义的


static {
 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
 CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
 sPoolWorkQueue, sThreadFactory);
 threadPoolExecutor.allowCoreThreadTimeOut(true);
 THREAD_POOL_EXECUTOR = threadPoolExecutor;
 }

可以看到这个是允许一定数量的子线程并行处理的。

其中参数是这么定义的


private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
 // We want at least 2 threads and at most 4 threads in the core pool,
 // preferring to have 1 less than the CPU count to avoid saturating
 // the CPU with background work
 private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
 private static final int KEEP_ALIVE_SECONDS = 30;

按照一般理解,允许同时运行的CORE进程是4个,MAXIMUM_POOL_SIZE是17个。(注:这个数字是我用荣耀8手机跑出来的,其他手机可能会有不同)

而Android中的AsyncTask提供了一个方法:


 public static void setDefaultExecutor(Executor exec) {
 sDefaultExecutor = exec;
 }

所以规避方法是:通过这个方法可以设置默认的Exector,但是这个方法是hide的,也就是Google的隐藏方法,估计需要用一下反射来处理。我偷个懒,不去实现了。

4、总结

本来嘛,我只是想简单写一下AsyncTask的一些相关知识,Copy一下网上的内容,但是没有想到写到最后,发现网上的大部分东西是错的,或者没有抓到重点。看来以后还是要自己亲自看代码,纸上得来终觉浅,便知此事要躬行。

本文中用到的工程代码可以到我的github中查看,路径:https://github.com/YanYoJun/AsyncTaskTest

您可能感兴趣的文章:浅谈Android AsyncTask内存安全的一种使用方式详解spring/Spring Boot异步任务编程WEBAsyncTaskSpring Boot 使用WebAsyncTask异步返回结果Android中使用AsyncTask实现下载文件动态更新进度条功能Android AsyncTask的缺陷和问题总结Android使用AsyncTask下载图片并显示进度条功能Android带进度条的下载图片示例(AsyncTask异步任务)Android 中使用 AsyncTask 异步读取网络图片Android使用AsyncTask加载图片的操作流程


--结束END--

本文标题: Android AsyncTask的优缺点详解

本文链接: https://www.lsjlt.com/news/22196.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 在Android开发中使用 AsyncTask的缺点有哪些
    今天就跟大家聊聊有关在Android开发中使用 AsyncTask的缺点有哪些,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。在Android开发中,AsyncTask可以使...
    99+
    2023-05-31
    android asynctask cta
  • Android多线程AsyncTask详解
    本篇随笔将讲解一下Android的多线程的知识,以及如何通过AsyncTask机制来实现线程之间的通信。一、android当中的多线程在Android当中,当一个应用程序的组件启动的时候,并且没有其他的应用程序组件在运行时,Android系...
    99+
    2023-05-30
    android 多线程 asynctask
  • React hooks的优缺点详解
    目录前言 优点:缺点:一、响应式的useEffect 二、状态不同步 怎么避免react hooks的常见问题 前言 Hook 是 React 16.8 的新增特性。它是完全可选的...
    99+
    2024-04-02
  • golang函数的优缺点详解
    go 函数的优缺点:优点:可重用性:可重复使用,无需复制代码。封装:隐藏实现细节,提高代码可读性。测试性:易于单独测试,有助于捕获错误。性能:高效,编译时直接转换为机器码。缺点:内存开销...
    99+
    2024-04-20
    函数 golang 代码可读性
  • android compose的优缺点有哪些
    Android Compose是一种用于构建用户界面的声明性UI工具包,它具有以下几个优点和缺点:优点:1. 声明性:Android...
    99+
    2023-10-19
    android
  • android中leanback的优缺点是什么
    leanback是Android中专门为TV和其他大屏设备设计的UI框架。它的优缺点如下: 优点: 适配大屏幕设备:leanbac...
    99+
    2024-04-02
  • android中slider的优缺点是什么
    Slider是一种常用的用户界面控件,用于在移动设备上选择数值范围。在Android中,Slider控件也被广泛应用,其优缺点如下:...
    99+
    2024-04-08
    android
  • android中mediasession的优缺点是什么
    MediaSession 是 Android 提供的一个用于管理媒体播放的类,主要用于在应用程序和系统之间传递媒体播放相关的信息和命...
    99+
    2024-03-06
    android
  • android中platform tools的优缺点是什么
    Android中的Platform Tools是一个包含了一系列用于开发和调试Android设备的工具集合,包括ADB(Androi...
    99+
    2024-04-02
  • android约束布局的优缺点是什么
    Android约束布局(ConstraintLayout)是一种相对布局,可以通过设置各种约束条件来定义视图之间的关系。它的优点和缺...
    99+
    2023-08-16
    android
  • android的四大组件有哪些优缺点
    Android的四大组件包括Activity、Service、BroadcastReceiver和ContentProvider,它...
    99+
    2023-09-15
    android
  • vue混入mixin流程与优缺点详解
    目录1、什么是mixin2、mixin与Vuex的区别3、mixin的使用3.1、局部混入3.2、全局混入4、mixin选项合并4.1、生命周期函数4.2、data中的数据冲突4.3...
    99+
    2024-04-02
  • Python 异步编程:path 框架的优缺点详解
    随着互联网的发展,越来越多的应用程序需要处理大量的并发请求。在传统的同步编程模型中,一旦一个请求被处理,程序就会一直等待下一个请求的到来。这种模式无法满足高并发应用的需求。因此,异步编程模型应运而生。 Python 是一门优秀的异步编程语...
    99+
    2023-11-10
    异步编程 框架 path
  • Angular的优缺点
    一、优点 完整的框架: Angular是一个全面的框架,提供了开发SPA所需的一切,如数据绑定、依赖注入、路由等。 TypeScript支持: Angular使用TypeScript进行开发,这为开发者提供了静态类型检查,可以提...
    99+
    2023-10-29
    优缺点 Angular
  • C++ 友元函数详解:友元函数的优点和缺点?
    友元函数是一种特殊函数,可以访问另一个类的私有和受保护成员,优点包括跨类访问私有数据、增强封装、提高代码可重复性。缺点则包括破坏封装、增加耦合度、降低代码可读性。 C++ 友元函数详解...
    99+
    2024-04-28
    c++ 友元函数 封装性 代码可读性
  • Python的优点和缺点
    本节内容如下: Python的优点 Python的缺点 使用Python的知名网站 Python的优点 1. 简单 Python的语法非常优雅,甚至没有像其他语言的大括号,分号等特殊符号,代表了一种极简主义的设计思想。阅读Pyth...
    99+
    2023-01-31
    优点 缺点 Python
  • React 高阶组件与Render Props优缺点详解
    目录高阶组件增强型高级组件注入型高阶组件高阶组件 VS Render Props总结高阶组件 高阶组件(HOC)是一个接受组件作为参数并返回一个新组件的函数,如果多个组件有相同的逻辑...
    99+
    2022-11-16
    React 高阶组件 Render Props Render Props
  • golang的优点以及缺点
    golang 是一款高性能、并发处理强大的编程语言,语法简洁,跨平台。它的优点还包括高效并发、丰富的库和工具生态系统。不过,golang 也存在一些缺点,如面向对象编程有限、缺乏泛型、对...
    99+
    2024-04-21
    linux python golang macos
  • HTTPS的优缺点和原理解析
    这篇文章主要讲解了“HTTPS的优缺点和原理解析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“HTTPS的优缺点和原理解析”吧!HTTPS是什么:HTTPS(全称:Hyper Text Tr...
    99+
    2023-06-10
  • Lombok的详细使用及优缺点总结
    什么是Lombok Lombok是一款Java开发插件,可以通过它定义的注解来精简冗长和繁琐的代码,主要针对简单的Java模型对象(POJO)。 好处就显而易见了,可以节省大量重复工...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作