Android 深入理解Loader机制 让APP轻装上阵
本文简书同步发布,谢谢关注。
Android开发者都经历过APP UI开发不当 会造成overDraw,导致APP UI渲染过慢,但是很多人却没听过overLoad,overLoad一般是由于开发者在主线程操作耗时操作,导致程序变慢 甚至出现的anr的现象,那么android早已为这种现象提供完美的解决方案,就是今天给大家说的Loader机制。
一 Loader
Android的装载器(loader)是从Android 3.0新引入的API , 主要完成单线程耗时数据异步装载功能,并在数据有更新自动通知UI刷新的作用。业内也叫加载器,装载机,
Loader用途
Loader一般用在Activity和fragment异步加载数据,无需重新启动一个线程来执行数据加载,异步加载可以用asyncTask, 但是loader自带数据结果监听机制,可以方便优雅的进行UI更新。
作用和优点:
提供异步加载数据功能
对数据源变化进行监听,实时更新数据
在Activity配置发生变化(如横竖屏切换)时不重复加载数据
支持任何Activity和Fragment
加载耗时数据常用方式
android开发者都知道不能再UI线程里去执行耗时操作,甚至在4.0里已经无法再主线程里去访问网络,那么一般加载耗时操作有以下办法。
1 2B加载
2 普通加载
3 文艺加载
为何说1和2是不可取呢,我们从Loader源码看起
**
二 Loader实现
**
Loader源码在android.content下面,可见它的份量有多重,loader机制,包括LoaderManager,Loader,LoaderCallbacks三部分,
LoaderManager 来管理我们的laoder实例,获取来初始化,重启一个loader,
Loader 来执行我们的异步操作,有开始,完成,后台等接口实现
LoaderCallbacks 来执行我们的loader回调,主要是绑定分发Loader,完成加载,重置数据等。
流程如下图:
1 LoaderManager
LoaderManager是抽象类,负责管理一组Loader主要定义执行Loader的一些抽象方法,类结构如下图:
从上图看以看出,Ta里面主要初始化loader,获取 重启,销毁一个loader,也包含一个内部成员变量LoaderCallback回调,主要方便我们在上层操作,但真正是由他的实现类LoaderManagerImpl去完成操作的
LoaderManagerImpl 记录着一组LoaderInfo信息,持有LoaderManager.LoaderCallbacks, mLoader等成员,负责对Loader和LoaderCallbacks的对应回调,内部基于观察者模式实现,源码不在解读;
2 Loader
Loader是具体来操作任务的类,负责去调用不同渠道的数据接口,比如数据库,contentProvider,文件等。
从大致的uml图我可以了解loader持有一个内部观察者,和一些注册监听的内部方发,已经暴露出来的对加载操作的状态步骤,有加载中,取消加载,强制加载,内容发生改变等,
在平常的开发中,谷歌问我们提供了laoder的子类,AsyncTaskLoader,CursorLoader等子类, 源码不在介绍,现在说下他们的不同点。CursorLoader又是AsyncTaskLoader的子类,主要负责数据库查询的异步加载,AsyncTaskLoader可用来所有异步加载。
2.1 AsyncTaskLoader
AsyncTaskLoader集成Loader, 除了拥有loader的功能,还有executePendingTask(), dispatchOnCancelled(),onLoadInBackground(),最神奇的是他拥有AsyncTask的实例,并且实现Runnable,这是他能进行异步的原因所在,看代码,对AsyncTask不熟悉的请移步安卓 《AsyncTask深度解析》自我补脑,
笔者看了源码,AsyncTaskLoader拥有AsyncTask,在自身实例化后开启一个线程,自我进行executePendingTask(),此方法里其实就在执行asyncTask的mTask.executeOnExecutor(mExecutor,(Void[])null);来实现AsyncTaskLoader的自我监听机制,当然自身轮询和传输是离不开Handler mHandler的 因为整个android的通讯就是建立在Handler(底层binder)基础上,这里不再分析。
2.2 CursorLoader
CursorLoader是AsyncTaskLoader的子类,内部持有ForceLoadContentObserver变量,为实现对数据源的数据更新,执行加载数据操作然离不开查询操作,内部主要代码:
三 怎么使用loader
1 注册Loader
Activity初始化在oncreate()初始化,一个Activity或Fragment中LoaderManager管理一个或多个Loader实例,每个Activity或Fragment只有一个LoaderManager,我们可以在Activity的onCreate()或Fragment的onActivityCreated()里初始化一个Loader。例如:
getLoaderManager().initLoader(0, null, new DataLoaderCallback());
可以看见上面的initLoader()方法有三个参数:
第一个参数代表当前Loader的ID ,用来区分那个loader;
第二个参数代表提供给Loader构造函数的参数,Bundle对象类型
可选;第三个参数代表LoaderManager.LoaderCallbacks的回调实现 需要我自我实现。;
上面initLoader()方法的调用一个Loader被初始化和激活的状态,该方法的调运有如下两种结果:
如果代表该Loader的ID已经存在,则后面创建的Loader将直接复用已经存在的;
如果代表该Loader的ID不存在,initLoader()会触发LoaderManager.LoaderCallbacks回调的onCreateLoader()方法创建一个Loader;
可以看见通过initLoader()方法可以将LoaderManager.LoaderCallbacks实例与Loader进行关联,且当Loader的状态变化时就被回调。所以说,如果调用者正处于其开始状态并且被请求的Loader已经存在,且已产生了数据,那么系统会立即调用onLoadFinished()(在initLoader()调用期间),所以你必须考虑到这种情况的发生。
当然了,intiLoader()会返回一个创建的Loader,但是你不用获取它的引用,因为LoadeManager会自动管理该Loader的生命周期,你只用在它回调提供的生命周期方法中做自己数据逻辑的处理即可。
2 * 实现LoaderManager Callbacks接口*
LoaderManager.LoaderCallbacks是LoaderManager的回调交互接口。LoaderManager.LoaderCallbacks包含以下三个方法:
onCreateLoader()
实例化并返回一个新创建给指定ID的Loader对象,第一次创建是回调;
onLoadFinished()
数据load完成之后回调此方法;
onLoaderReset()
当创建好的Loader被reset时调用此方法,重新清楚绑定好的数据,重新加载数据;
3 Loader使用实例
1》 初始化loader
getLoaderManager().initLoader(0, null, new DataLoaderCallback());
2》实现callback接口,处理回调
当然你也可以用来绑定谷歌提供的CursorLoader ,在Loader创建的时候被调用,这里使用一个ContentProvider获取数据,所以使用CursorLoader返回数据
3》 继承Loader,数据绑定,和数据适配
在这里我们模拟了构造一组数据,当然你也可以在loadInBackgruond去读文件,访问网络,查询数据库
4 拓展
1》 用来自动刷新ContentPorvider
在我们使用CurSorLoader时大家都会考虑一种情况的处理—–当数据库发生变化时如何自动刷新当前UI,数据库在数据改变时通过ContentPorvider和ContentResolver发出通知,接着ContentProvider通知Cursor的观察者数据发生了变化,然后Cursor通知CursorLoader的观察者数据发生了变化,然后CursorLoader通过ContentProvider加载新数据,完事调用CursorAdapter的changeCursor()用新数据替换旧数据显示。
这个过程具体的实现步骤如下:
对获取的Cursor数据设置需要监听的URI(即,在ContentProvider的query()方法或者Loader的loadingBackground()方法中调用Cursor的setNotificationUri()方法);
在ContentProvider的insert()、update()、delete()等方法中调用ContentResolver的notifyChange()方法;
通过上面两步我们就能享受CurSorLoader的自动数据刷新功能了;可以发现,所谓的CurSorLoader自动刷新也是对文章开头说的观察者模式,所以不再过多说明。
2》不使用ContentPorvider的自动刷新
四 Loaders相关源码流程:
通过上面我们的源码分析和分析前那副图可以总结如下结论:
一次完整的数据加载流程为Activity调用LoaderManager的doStart()方法,然后LoaderManager调用Loader的startLoading()方法,然后Loader调运AsyncTaskLoader的doingBackground()方法进行耗时数据加载,然后AsyncTaskLoader回调LoaderManager的complete数据加载完成方法,接着LoaderManager回调我们在Activity中实现的callback中的onLoadFinish()方法。
Acivity和Fragment的生命周期主动管理了LoaderManager,每个Activity用一个ArrayMap的mAllLoaderManager来保存当前Activity及其附属Frament的唯一LoaderManager;在Activity配置发生变化时,Activity在destory前会保存mAllLoaderManager,当Activity再重新创建时,会在Activity的onAttcach()、onCreate()、performStart()方法中恢复mAllLoaderManager。
LoaderManager给Activity提供了管理自己的一些方法;同时主动管理了对应的Loader,它把每一个Loader封装为LoadInfo对象,同时它负责主动调运管理Loader的startLoading()、stopLoading()、,forceLoad()等方法。
由于整个Activity和Fragment主动管理了Loader,所以关于Loader的释放(譬如CursorLoader的Cursor关闭等)不需要我们人为处理,Loader框架会帮我们很好的处理的;同时特别注意,对于CursorLoader,当我们数据源发生变化时Loader框架会通过ContentObserver调用onContentChanged的forceLoad方法重新请求数据进行回调刷新。
五 总结
以上Loader机制、源码分析、拓展你会发现Loader强大的强大之处,比如普通展现某个android手机有多少应用程序,加载已安装app时候,其实loader就能排上用场, 详细见谷歌对介绍:
https://developer.android.com/reference/android/content/AsyncTaskLoader.html。
PS:顺便说下AsyncTaskLoader与AsyncTask的区别,看完源码我们再回过头来总结性的说说他们二者区别,如下:
最主要是加载数据,使用loader我们无须关注数据何时改变了,也无需关注activity的生命周期,做到数据不被重复多次加载情况,做到一次加载多次使用的效果,我们可以拿着loader变活灵通,这里的博大精深还需要读者自我体会。
**
实例代码下载
:https://github.com/NeglectedByBoss/Loader
**
Android 深入理解Loader机制 让APP轻装上阵的更多相关文章
- 深入理解android的UI更新机制
深入理解android的UI更新机制 由问题开始: 如何更新android UI? 可以通过如下方法: 在主线程里直接操作UI控件. handler.post(Runnable) runOnUiThr ...
- [Android] Android 用于异步加载 ContentProvider 中的内容的机制 -- Loader 机制 (LoaderManager + CursorLoader + LoaderManager.LoaderCallbacks)
Android 用于异步加载 ContentProvider 中的内容的机制 -- Loader 机制 (LoaderManager + CursorLoader + LoaderManager.Lo ...
- android的事件分发机制理解
android的事件分发机制理解 1.事件触发主要涉及到哪些层面的哪些函数(个人理解的顺序,可能在某一层会一次回调其它函数) activity中的dispatchTouchEvent .layout中 ...
- Android线程间通信机制——深入理解 Looper、Handler、Message
在Android中,经常使用Handler来实现线程间通信,必然要理解Looper , Handler , Message和MessageQueue的使用和原理,下面说一下Looper , Handl ...
- 谈谈对Android中的消息机制的理解
Android中的消息机制主要由Handler.MessageQueue.Looper三个类组成,他们的主要作用是 Handler负责发送.处理Message MessageQueue负责维护Mess ...
- Android 操作系统的内存回收机制(转载)
Android 操作系统的内存回收机制(转载) Android APP 的运行环境 Android 是一款基于 Linux 内核,面向移动终端的操作系统.为适应其作为移动平台操作系统的特殊需要,谷歌对 ...
- (转)Android之接口回调机制
开发中,接口回调是我们经常用到的. 接口回调的意思即,注册之后并不立马执行,而在某个时机触发执行. 举个例子: A有一个问题不会,他去问B,B暂时解决不出来,B说,等我(B)解决了再告诉你(A)此时A ...
- Android Gradle 理解
/********************************************************************************* * Android Gradle ...
- 转: Android中的签名机制
转载请注明出处:http://www.blogjava.net/zh-weir/archive/2011/07/19/354663.html Android APK 签名比对 发布过Android应用 ...
随机推荐
- LGTB 与大数
LGTB 有一个非常大的数,并且他想对它进行Q 次操作 每次操作是把这个大数中的某种数字全部替换成一个数字串 他想知道Q 次操作之后得到的数对1000000007(109 + 7) 取模的结果,请输出 ...
- [Codeforces]856C - Eleventh Birthday
题目大意:给出n个数,问有多少种排列把数字接起来是11的倍数.(n<=2000) 做法:一个数后面接一个数等同于乘上10的若干次幂然后加上这个数,10模11等于-1,所以10的若干次幂是-1或1 ...
- 【USACO Feb 2014】Cow Decathlon
题目描述 约翰有 N 头奶牛,组成了一直队伍参加全能比赛.比赛一共有 N 项,每头奶牛必须参加一项比 赛,每项比赛也必须有一头奶牛参加.任何一头奶牛可以胜任任何一项比赛,但得分不一样.如果第 i 头奶 ...
- hdu 1890 splay树
Robotic Sort Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tot ...
- 开发者说 | 使用Visual Studio Code编译、调试Apollo项目
转载地址:https://mp.weixin.qq.com/s?__biz=MzI1NjkxOTMyNQ==&mid=2247484266&idx=1&sn=d6bcd4842 ...
- jvm 指令集代码
指令码 助记符 说明 0x00 nop 什么都不做 0x01 aconst_null 将null推送至栈顶 0x02 iconst_m1 将int型-1推送至栈顶 0x03 iconst_0 将int ...
- jQuery extend 方法使用 (转)
方法介绍 jQuery 的 API 手册中,extend 方法挂载在 jQuery 和 jQuery.fn 两个不同的对象上,但在 jQuery 内部代码实现的是相同的,只是功能各不相同. 先看看官方 ...
- Parallel.For 平行算法 使用
之前看到Parallel的用法,觉得很高深,很腻害,今天专门抽空研究了一下,发现还是很easy的. .NET Framework 4.0 新加的功能,所以4.0之前的无法使用哦. 下面介绍一下,Par ...
- HybridAPP开发框架Ionic+AngularJS+Cordova搭建
Ionic Ionic是一个新的.可以使用HTML5构建混合移动应用的用户界面框架,它自称为是"本地与HTML5的结合".该框架提供了很多基本的移动用户界面范例,例如像列表(lis ...
- Ubuntu16.04下安装jdk1.8过程
笔者环境:腾讯云服务器 Ubuntu16.04 x64 一 . 去oracle官网下载对应的jdk 下载地址:http://www.oracle.com/technetwork/java/javase ...