目录:

  • Android的线程和内存模型
  • AsyncTask
    • 碎片化问题
    • Activity生命周期问题
  • Handler & HandlerThread
    • Looper
  • Loader
    • AsyncTaskLoader
    • CursorLoader
  • IntentService
  • Service
  • AlarmManager
  • 参考链接

Android的线程和内存模型

Android操作系统在boot后,会启动一个Zygote(受精卵)进程,Zygote进程负责创建大部分应用程序进程。Zygote进程启动加载核心程序库和数据结构到内存后会创建一个Dalvik虚拟机(DVM)进程--SystemServer,此进程会包含大部分的系统服务(包括管理Activity的服务ActivityManagerService),SystemServer初始化后,Zygote进程会侦听本地的socket端口, 等待进一步的指令。当新的app被启动时,Zygote会为这个app创建一个DVM—-直接fork出一个子进程,这种架构的好处是同时启动多个App时,多个App进程可以访问共享内存。

Android App的进程也是一个DVM,内部有许多线程在执行,比如,主UI线程(Main Thread),垃圾回收线程等。其中主UI线程负责执行我们写的应用代码。对于只做很少的I/O操作或耗时操作的App,单一线程开发模式问题不大,但是如果有大量IO或者CPU计算的任务,我们就必须在其他线程内完成了。

因为主UI线程需要根据硬件刷新率[^3]同步用户界面的重绘。手机应用体验流畅要求界面帧率[^3]达到每秒60,也就是说每16.67毫秒就需要重绘一帧,这意味着如果我们在主线程上执行的任务超过16毫秒,就会出现丢帧现象,也就是界面会开始变卡。。。

Android异步执行任务的方法有以下几种:

AsyncTask

AsyncTask是最常用的异步方法,功能结构设计的也很丰富,给使用者足够的控制,使用上主要是将异步执行的任务放在下面方法里。

  1. protected Result doInBackground(Params... params)

然后调用.execute(params)方法即可。

AsyncTask的执行逻辑在API Level 3只能串行执行, 在API Level 4改成了最多128个线程的线程池执行,API Level 11则改成了缺省所有的AsyncTask是在一个线程中顺序执行的,这样可以保证执行和提交的次序一致,如果希望能并发的执行,可以用下面的方法在线程池内执行:

  1. task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);

AsyncTask.THREAD_POOL_EXECUTORThreadPoolExecutor的一个实例,配置是最少5个线程,最多128个。如果需要自己来配置线程池大小,你可以传递自己配置的一个实例到上述方法。

使用AsyncTask需要注意的几个问题:

碎片化问题

因为不同版本的Android AsyncTask缺省执行逻辑并不一样,可能在不同机型上表现不一致。如果要自己控制AsyncTask的并发度,解决这个问题的建议是复制Android SDK的AsyncTask源码自己实现一个AsyncTask。

Activity生命周期问题

Activity可能早于AsyncTask执行完被销毁,如果AsyncTask还继续执行,有可能会浪费资源,并且如果AsyncTask里引用了Activity或部分的View Hierarchy,还会造成引用的对象不会被垃圾回收而引起内存泄漏。通常AsyncTask会定义为Activity的一个匿名inner class,这会建立一个隐式的引用到Activity。

解决的方法是:

  1. 在Activity里的onPause方法里及时取消不需要再执行的AsyncTask(这种方法在切换到横屏时会重启异步任务,有点浪费)
  2. 更好的是使用retained headless fragment来解决生命周期问题,具体演示代码见参考链接

Async比较合适的是较短的(1,2秒),CPU密集计算或读写文件等阻塞IO操作。耗时较长的网络调用用Async不是最合适的。

Handler & HandlerThread

Handler的异步编程是基于消息队列模型的。执行任务的线程称之为Looper线程,其他线程则将需要异步执行的任务发送给Looper线程–插入其消息队列,方法有:post(较方便使用,但每次需要创建新对象)或sendMessage(较高效,复用消息实例,适合执行大量类似的异步任务)

Looper

Looper和它的名字意思一样就是Looper线程会永远循环,当没有消息的时候,Looper线程(消费者)会使用(Object.wait)方法等待其他线程(生产者)插入新的任务消息,这时候其他线程(Object.notify)

Android的主线程其实就是一个Looper线程。

需要注意的是,使用Handler和AsyncTask一样,要注意匿名inner class对Activity的隐式引用而造成内存泄漏,所以使用的时候要记得清理;

解决方法是使用对使用的Activity中的View对象用Weak Reference,并处理当View对象为null的情况。

Handler适合更长一点的(>2秒)的异步任务处理。

Loader

Loader在Android编程框架中被广泛用于后台加载数据(从文件,数据库甚至网络)。

AsyncTaskLoader

具体的Loader实现。

CursorLoader

用户数据库数据后台加载。

Loader在使用上比较大的优势是和Activity的部分解耦,更见到的生命周期管理。

IntentService

IntentService是Service的一个实现类。其内部实现包含了一个HandlerThread,当任务提交给IntentService时,会被加到队列并顺序处理。

  1. public class MyIntentService extends IntentService {
  2. public MyIntentService() {
  3. super("thread-name");
  4. }
  5. protected void onHandleIntent(Intent intent) {
  6. // executes on the background HandlerThread.
  7. }
  8. }
  9. Intent intent = new Intent(context, MyIntentService.class);
  10. intent.setData(uri); intent.putExtra("param", "some value");
  11. startService(intent);

IntentService返回任务结果给Activity可以有下面几种方法(Service和Activity的通信方法):

  1. Activity启动IntentService时候,传递一个PendingIntent对象给IntentService,IntentService在处理完任何后调用PendingIntent.send()通知Activity,Activity在onActivityResult方法内处理收到的消息。
  2. 提交一个系统通知,这样App不在前台,用户也可以知道任务完成,比如下载地图数据。
  3. 使用Messenger发送一个消息给Activity里的Handler。
  4. 使用广播方式把结果封装在Intent中广播出去, 这样Fragment或Activity都可以通过监听广播获得处理结果。

IntentService可以完全和Activity解耦。适合即使App主界面退出情况下也必须完成的任务,比如后台上传日志,图片之类的任务。

Service

Service合适执行独立于任何Activity或Fragment的任务,即使App主界面退出情况下也必须完成的任务;或者需要比IntentService更高或更细致的并发控制。

AlarmManager

AlarmManager可以不在人工干预下定时执行任务,比如定时检查邮件,下载更新,或同步内容到云端。

参考链接

  1. Asynchronous Android
  2. Android内核
  3. 帧率与刷新率的区别
原文地址:http://hugozhu.myalert.info/2014/06/29/46-async-android.html

Android异步编程相关推荐

  1. Android 异步编程

    文章转载自:http://www.oschina.net/question/54100_160305 文章作者:朱鸿,淘宝资深架构师 原文出处:http://hugozhu.myalert.info/ ...

  2. android异步编程,AsyncTask简单的异步编程android 中的实现

    类型:行业软件大小:1.5M语言:中文 评分:5.0 标签: 立即下载 在开发移动客户端的时候往往要使用多线程来进行操作,我们通常会将耗时的操作放在单独的线程执行,避免其占用主线程而给用户带来不好的用 ...

  3. android 异步编程,flutter异步编程-事件循环、Isolate、Stream(流)

    事件循环.Isolate 开始前我们需要明白 Dart 是单线程的并且 Flutter 依赖于 Dart 如果你知道js 中的event loop 将很好理解dart的整个异步过程 先看一段代码 im ...

  4. 异步编程 In .NET(转载)

    概述 在之前写的一篇关于async和await的前世今生的文章之后,大家似乎在async和await提高网站处理能力方面还有一些疑问,博客园本身也做了不少的尝试.今天我们再来回答一下这个问题,同时我们 ...

  5. 《Android游戏编程入门经典》——1.7节小结

    本节书摘来自异步社区<Android游戏编程入门经典>一书中的第1章,第1.7节小结,作者[美]Jonathan S. Harbour,更多章节内容可以访问云栖社区"异步社区&q ...

  6. Java 异步编程:从 Future 到 Loom

    众所周知,Java 开始方法执行到结束,都是由同一个线程完成的.这种方式虽易于开发调试,但容易因为锁.IO 等原因导致线程挂起,产生线程上下文切换.随着对应用并发能力要求越来越高,频繁的线程上下文切换 ...

  7. 异步编程到底在说啥?

    作者 | 码农的荒岛求生 来源 | 码农的荒岛求生 之前很多同学在微信上问能不能讲讲异步编程是怎么一回事儿,今天就和大家简单聊一聊这个话题. 我们以函数调用为例,假设有这样的代码: void B() ...

  8. java coroutine类_Coroutines和Rxjava异步编程对比

    这一系列的文章将会用来进行Coroutines和Rxjava在解决异步编程方面的对比. 案例一:为一个快速启动的App创建复杂的对象 如果希望自己的应用程序能够快速启动,那么处理创建对象的过程非常重要 ...

  9. android: 多线程编程基础

    9.1   服务是什么 服务(Service)是 Android 中实现程序后台运行的解决方案,它非常适合用于去执行那 些不需要和用户交互而且还要求长期运行的任务.服务的运行不依赖于任何用户界面,即使 ...

最新文章

  1. cmakelist 定义变量
  2. 【指标统计】删除抖动遥信
  3. 安卓dts音频解码_DTS音效、解码、编码概念剖析
  4. 取表单radio值时
  5. 学位论文盲审被卡,或直接被毙,问题主要出在这几条!
  6. C++设计模式-组合模式
  7. qt5中重绘工具栏_Qt ------ QPainter 和控件组件的重绘
  8. JavaScript 学习笔记— —Arguments
  9. python编程符号大全_2020 年最值得学习的 5 大 AI 编程语言
  10. 2.7 if应用:猜拳游戏
  11. ab压力测试工具详解
  12. 基于遗传算法的新安江模型参数优化率定(二)
  13. 3D GAME PROGRAMMING WITH DIRECTX11 (1)
  14. python图片logo_Python logo
  15. word2vec教程
  16. seed lab 2020 packet sniffing and spoofing lab
  17. 恒压板框过滤实验数据处理_内江靠谱压滤机板框-清源环保
  18. tig git的好搭档
  19. python爬虫进阶案例,Python进阶(二十)-Python爬虫实例讲解
  20. RT-ThreadXSTM32F407智能车培训报名啦!

热门文章

  1. Linux企业级项目实践之网络爬虫(28)——爬虫socket处理
  2. c程序内存分布[转载]
  3. .net上传,一个选择直接上传(ashx)和byteArray上传
  4. 系统安装重装与优化:chapter7 操作系统的修复与重装
  5. GPU 编程入门到精通(一)之 CUDA 环境安装
  6. [云炬创业基础笔记]第一章创业环境测试12
  7. 科大星云诗社动态20210315
  8. [云炬商业计划书阅读分享] 体育器材
  9. 解决Sublime Text打开C++文件出现中文乱码
  10. [2dPIC调试笔记]初始化变量1014(2)