Android异步编程
目录:
- 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是最常用的异步方法,功能结构设计的也很丰富,给使用者足够的控制,使用上主要是将异步执行的任务放在下面方法里。
protected Result doInBackground(Params... params)
然后调用.execute(params)
方法即可。
AsyncTask的执行逻辑在API Level 3只能串行执行, 在API Level 4改成了最多128个线程的线程池执行,API Level 11则改成了缺省所有的AsyncTask是在一个线程中顺序执行的,这样可以保证执行和提交的次序一致,如果希望能并发的执行,可以用下面的方法在线程池内执行:
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
AsyncTask.THREAD_POOL_EXECUTOR
是ThreadPoolExecutor
的一个实例,配置是最少5个线程,最多128个。如果需要自己来配置线程池大小,你可以传递自己配置的一个实例到上述方法。
使用AsyncTask需要注意的几个问题:
碎片化问题
因为不同版本的Android AsyncTask缺省执行逻辑并不一样,可能在不同机型上表现不一致。如果要自己控制AsyncTask的并发度,解决这个问题的建议是复制Android SDK的AsyncTask源码自己实现一个AsyncTask。
Activity生命周期问题
Activity可能早于AsyncTask执行完被销毁,如果AsyncTask还继续执行,有可能会浪费资源,并且如果AsyncTask里引用了Activity或部分的View Hierarchy,还会造成引用的对象不会被垃圾回收而引起内存泄漏。通常AsyncTask会定义为Activity的一个匿名inner class,这会建立一个隐式的引用到Activity。
解决的方法是:
- 在Activity里的
onPause
方法里及时取消不需要再执行的AsyncTask(这种方法在切换到横屏时会重启异步任务,有点浪费) - 更好的是使用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时,会被加到队列并顺序处理。
public class MyIntentService extends IntentService {
public MyIntentService() {
super("thread-name");
}
protected void onHandleIntent(Intent intent) {
// executes on the background HandlerThread.
}
}
Intent intent = new Intent(context, MyIntentService.class);
intent.setData(uri); intent.putExtra("param", "some value");
startService(intent);
IntentService返回任务结果给Activity可以有下面几种方法(Service和Activity的通信方法):
- Activity启动IntentService时候,传递一个PendingIntent对象给IntentService,IntentService在处理完任何后调用
PendingIntent.send()
通知Activity,Activity在onActivityResult
方法内处理收到的消息。 - 提交一个系统通知,这样App不在前台,用户也可以知道任务完成,比如下载地图数据。
- 使用Messenger发送一个消息给Activity里的Handler。
- 使用广播方式把结果封装在Intent中广播出去, 这样Fragment或Activity都可以通过监听广播获得处理结果。
IntentService可以完全和Activity解耦。适合即使App主界面退出情况下也必须完成的任务,比如后台上传日志,图片之类的任务。
Service
Service合适执行独立于任何Activity或Fragment的任务,即使App主界面退出情况下也必须完成的任务;或者需要比IntentService更高或更细致的并发控制。
AlarmManager
AlarmManager可以不在人工干预下定时执行任务,比如定时检查邮件,下载更新,或同步内容到云端。
参考链接
- Asynchronous Android
- Android内核
- 帧率与刷新率的区别
Android异步编程相关推荐
- Android 异步编程
文章转载自:http://www.oschina.net/question/54100_160305 文章作者:朱鸿,淘宝资深架构师 原文出处:http://hugozhu.myalert.info/ ...
- android异步编程,AsyncTask简单的异步编程android 中的实现
类型:行业软件大小:1.5M语言:中文 评分:5.0 标签: 立即下载 在开发移动客户端的时候往往要使用多线程来进行操作,我们通常会将耗时的操作放在单独的线程执行,避免其占用主线程而给用户带来不好的用 ...
- android 异步编程,flutter异步编程-事件循环、Isolate、Stream(流)
事件循环.Isolate 开始前我们需要明白 Dart 是单线程的并且 Flutter 依赖于 Dart 如果你知道js 中的event loop 将很好理解dart的整个异步过程 先看一段代码 im ...
- 异步编程 In .NET(转载)
概述 在之前写的一篇关于async和await的前世今生的文章之后,大家似乎在async和await提高网站处理能力方面还有一些疑问,博客园本身也做了不少的尝试.今天我们再来回答一下这个问题,同时我们 ...
- 《Android游戏编程入门经典》——1.7节小结
本节书摘来自异步社区<Android游戏编程入门经典>一书中的第1章,第1.7节小结,作者[美]Jonathan S. Harbour,更多章节内容可以访问云栖社区"异步社区&q ...
- Java 异步编程:从 Future 到 Loom
众所周知,Java 开始方法执行到结束,都是由同一个线程完成的.这种方式虽易于开发调试,但容易因为锁.IO 等原因导致线程挂起,产生线程上下文切换.随着对应用并发能力要求越来越高,频繁的线程上下文切换 ...
- 异步编程到底在说啥?
作者 | 码农的荒岛求生 来源 | 码农的荒岛求生 之前很多同学在微信上问能不能讲讲异步编程是怎么一回事儿,今天就和大家简单聊一聊这个话题. 我们以函数调用为例,假设有这样的代码: void B() ...
- java coroutine类_Coroutines和Rxjava异步编程对比
这一系列的文章将会用来进行Coroutines和Rxjava在解决异步编程方面的对比. 案例一:为一个快速启动的App创建复杂的对象 如果希望自己的应用程序能够快速启动,那么处理创建对象的过程非常重要 ...
- android: 多线程编程基础
9.1 服务是什么 服务(Service)是 Android 中实现程序后台运行的解决方案,它非常适合用于去执行那 些不需要和用户交互而且还要求长期运行的任务.服务的运行不依赖于任何用户界面,即使 ...
最新文章
- cmakelist 定义变量
- 【指标统计】删除抖动遥信
- 安卓dts音频解码_DTS音效、解码、编码概念剖析
- 取表单radio值时
- 学位论文盲审被卡,或直接被毙,问题主要出在这几条!
- C++设计模式-组合模式
- qt5中重绘工具栏_Qt ------ QPainter 和控件组件的重绘
- JavaScript 学习笔记— —Arguments
- python编程符号大全_2020 年最值得学习的 5 大 AI 编程语言
- 2.7 if应用:猜拳游戏
- ab压力测试工具详解
- 基于遗传算法的新安江模型参数优化率定(二)
- 3D GAME PROGRAMMING WITH DIRECTX11 (1)
- python图片logo_Python logo
- word2vec教程
- seed lab 2020 packet sniffing and spoofing lab
- 恒压板框过滤实验数据处理_内江靠谱压滤机板框-清源环保
- tig git的好搭档
- python爬虫进阶案例,Python进阶(二十)-Python爬虫实例讲解
- RT-ThreadXSTM32F407智能车培训报名啦!
热门文章
- Linux企业级项目实践之网络爬虫(28)——爬虫socket处理
- c程序内存分布[转载]
- .net上传,一个选择直接上传(ashx)和byteArray上传
- 系统安装重装与优化:chapter7 操作系统的修复与重装
- GPU 编程入门到精通(一)之 CUDA 环境安装
- [云炬创业基础笔记]第一章创业环境测试12
- 科大星云诗社动态20210315
- [云炬商业计划书阅读分享] 体育器材
- 解决Sublime Text打开C++文件出现中文乱码
- [2dPIC调试笔记]初始化变量1014(2)