1. 概述
最近看了三本性能优化相关的书,<Android 移动性能实战>,<Android 应用性能优化最佳实践>,<高性能Android应用开发>,两本是开发人员写的,一本是测试人员写的.发现对比来看有很多相通的地方.所以把三本书总结到一起.做一个系列的笔记.
整体上,内容都是分为ui,内存,文件,CPU.网络.电量.电量对我现在的阶段,不是很重要的东西,这里就随便记录一些.然后其他几个步骤大体是讲原理.讲常见的知识点,讲修复评测工具.因为涉及内容很广.所以我也把目前不是很了解的知识点额外记录下来了.文章中会做一些讲解.先看整体的思维导图吧.
2.ui优化
原理
1. 绘制原理
1.1 APP端
-
measure得到宽高,layout得到位置,draw得到内容,然后把产生的绘制数据,通过夸进程通信交给SurfaceFlinger处理
-
measure
测量的时候通过深度优先算法遍历整个view树进行测量,通过setMeasuredDimension设置具体的宽高,measure是先测量子view,最后在测量自己,
-
layout
布局时候也是深度优先算法.通过setFrame设置view的位置,不过是先确定自己的位置,在确定子view的位置.和measure相反
- draw
绘制过程就是一层一层的绘制图案
-- 引用链接 https://juejin.im/entry/58d37fb861ff4b006cb6670a
1.2 系统端
SurefaceFlinger和每个应用都创建一个SharedClient匿名共享内存来传输数据,SurfaceFlinger负责创建layer和客户端的surface建立链接,把layer刷新到屏幕上(这里我也不太懂.先这样记着)
在Android底层绘制系统中,SurfaceFlinger 为App进程创建具体的Surface, 在SurfaceFlinger里对应成Layer, 然后负责管理、合成显示。Layer是SurfaceFlinger 进行合成的基本操作单元。Layer是在应用请求创建Surface的时候在SurfaceFlinger内部创建,因此一个Surface对应一个 Layer.
Cpu先准备数据,通过Driver层(Cpu不能直接与Gpu通信,需要中间graphics Drvier层作为共享内存)把数据交个Gpu渲染
总的来看.绘制过程很像生产者消费者模式,APP生产,SurfaceFlinger消费.CPU生产,GPU消费.
图解安卓图形系统 https://blog.csdn.net/freekiteyu/article/details/79483406
老罗的文章. https://blog.csdn.net/Luoshengyang/article/details/7846923
2. 刷新机制
- 在一个典型的显示系统中,一般包括CPU、GPU、display三个部分, CPU负责计算数据,把计算好数据交给GPU,GPU会对图形数据进行渲染,渲染好后放到buffer里存起来,然后display(有的文章也叫屏幕或者显示器)负责把buffer里的数据呈现到屏幕上。
显示过程,简单的说就是CPU/GPU准备好数据,存入buffer,display每隔一段时间去buffer里取数据,然后显示出来。display读取的频率是固定的,比如每个16ms读一次,但是CPU/GPU写数据是完全无规律的。因此目的是为了使CPU/GPU可以同步上屏幕的刷新频率. - 屏幕刷新.CPU,Gpu,display讲解,https://blog.csdn.net/litefish/article/details/53939882
- VSYNC机制, 安卓4.1以后加入就是每16ms通知CPU开始计算下一帧的数据,传到到GPU渲染出来,好处是保证可以及时绘制出每帧数据.问题是屏幕绘制的频率和CPU的计算频率被统一.如果CPU的频率高于绘制频率.就会闲置资源.低于绘制频率还是会卡顿.所以加入双缓冲和三缓冲.
- 双缓冲.两个buff来接受要渲染的数据,哪个buffer里数据准备好了就渲染他.然后在使用另一个来回交替.还有第三个缓冲.用的时候很少.但是当屏幕使用buffer1渲染时,gpu 使用buffer2,而此时如果CPU空闲,他可以把内容绘制到buffer3上.提高了CPU利用.
安卓中其实是三缓冲技术.
*双缓冲讲解https://souly.cn/%E6%8A%80%E6%9C%AF%E5%8D%9A%E6%96%87/2015/08/22/android%E5%9E%82%E7%9B%B4%E5%90%8C%E6%AD%A5%E5%92%8C%E4%B8%89%E9%87%8D%E7%BC%93%E5%AD%98/
3. 卡顿原因
- 绘制任务太重,一帧耗时太长,没能在16ms里执行完成--view视图树层级太多.
- 主线程进行其他计算,导致没能及时完成一帧数据的计算--主线程被其他任务占据太多时间
案例
- 减少层级视图.加快view的绘制时间,RelativeLayout会measure两次,LinearLayout设置weight也会测量两次
- layout.xml文件最外层的layout如果没什么功能,用merge代替.merge标签使子元素添加到merge标签的parent中.
- 使用viewStub轻量布局,
- 尽量少用wrap_content,会增加measure的计算时间.
- 自定义view时使用canvas.clipRect来避免过度绘制
- 减少屏幕的重复绘制,去掉window和不重要的layout层的背景.
- 减少重绘区域.自定义view用 canva.cliRect来确认需要重绘的区域
- 加入动画,进度条掩盖卡顿.推荐属性动画性能最高,重绘次数最少
- 减少ui刷新次数,这里指resyclerView这类.进行局部刷新
- 开启硬件加速.可以针对application,activity,window,view开启(textView加载很多中文时开启硬件加速会很卡)
- 减少屏幕过渡绘制
3.内存优化
原理
1. java对象声明周期
- created 分配空间,初始化static变量和成员变量
- inuse 至少被一个强引用对象所持有.
- invisible 没有被程序的任何强引用所持有.但可能被某些虚拟机下静态变量或者jni等强引用所持有
- unreachable 不可达,在不可见的基础上,也没被任何虚拟机或jni等强引用所持有.总是就是没有任何对象锁持有.
- collected 对象是不可达状态,且垃圾收集器准备回收这段内存了.就变成收集阶段.如果对象重写了finanlize方法,会执行finanlize
- finanlized 对象的finanlize方法执行完成后仍处于不可达状态.就进入终结阶段等待回收
- deallocated 垃圾回收对这段内存进行回收.对象彻底消失.
综上所述,当对象处于3却没法到达4的状态时,就是对象发生了内存泄露.
解释连接 https://www.jianshu.com/p/72a0e26d35bc
2. 内存分配
安卓的所有进程都是从zygote进程中fork出来的.安卓通过显示分配共享内存区域来实现不同进程之间共享RAM的机制.例如farmwork的代码.基础的so库.都是所有进程共享的.但是每个进程也有自己独立的内存. 独立的内存就是Uss,共享内存加独立的内存就是Pss.
而安卓虚拟机中又把内存对分成不同的区块.
- zygot space 在zygote进程和应用进程中共享.
- alloc space 和main alloc space 是每个进程独占
- linearalloc 是现行只读内存空间,用来存放虚拟机中的类
- image space 用来存放一些预加载类
- large obj space 是存放大对象的空间.art虚拟机把bitmap 用这块内存中加载
这里目前的水平也就是大概了解下.其实并不知道具体的含义.
资料文章https://www.jianshu.com/p/106795175971
3. 内存回收机制
安卓内存分为三个区域,年轻代,年老代,持久代.三个区域采用不同的gc算法.当对象在年轻代中经历几次gc还没被杀死.就进入了年老代.同样,在停留达到一定时间就进入持久代,持久代中也存放静态的方法和类,持久代对gc没什么效果.
年轻代又分成三个区,他采用copying算法,他进行gc更加频繁,但gc的速度也相对更快
copying 算法
将现有的内存空间分为两快,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,
之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收
年老代对象存活时间比较长.采用标记Mark算法.
标记回收算法(Mark and Sweep GC)
从"GC Roots"集合开始,将内存整个遍历一次,保留所有可以被GC Roots直接或间接引用到的对象,而剩下的对象都当作垃圾对待并回收,
这个算法需要中断进程内其它组件的执行并且可能产生内存碎片
标记-压缩算法 (Mark-Compact)
先需要从根节点开始对所有可达对象做一次标记,但之后,它并不简单地清理未标记的对象,而是将所有的存活对象压缩到内存的一端。之后,清理边界外所有的空间。
这种方法既避免了碎片的产生,又不需要两块相同的内存空间,因此,其性价比比较高。
关于算法和内存堆的详细讲解 https://www.jianshu.com/p/106795175971
垃圾回收讲解 https://blog.csdn.net/omnispace/article/details/50991489
4. Gc类型
GC_FOR_MALLOC: 表示是在堆上分配对象时内存不足触发的GC。 这种gc会在并发时停止所有线程.会卡顿.
GC_CONCURRENT: 当我们应用程序的堆内存达到一定量,或者可以理解为快要满的时候,系统会自动触发GC操作来释放内存。
GC_EXPLICIT: 表示是应用程序调用System.gc、VMRuntime.gc接口或者收到SIGUSR1信号时触发的GC。
GC_BEFORE_OOM: 表示是在准备抛OOM异常之前进行的最后努力而触发的GC。
5. 内存抖动
内存抖动是由于短时间内有大量对象进出Young Generiation区导致的,它伴随着频繁的GC.就是短时间大量申请对象,然后曲线上涨,但是触发多次gc又导致曲线下降.因此我们要避免短时间创建对象.一般就是循环,或者重复调用的方法中避免创建对象.
- 尽量避免在循环体内创建对象,应该把对象创建移到循环体外。
- 注意自定义View的onDraw()方法会被频繁调用,所以在这里面不应该频繁的创建对象。
- 当需要大量使用Bitmap的时候,试着把它们缓存在数组中实现复用。
- 对于能够复用的对象,同理可以使用对象池将它们缓存起来。
6. 安卓内存警告 OnTrimMemory
OnTrimMemory是Android在4.0之后加入的一个回调,任何实现了ComponentCallbacks2接口的类都可以重写实现这个回调方法.OnTrimMemory的主要作用就是指导应用程序在不同的情况下进行自身的内存释放,以避免被系统直接杀掉.
警告类型
- TRIM_MEMORY_RUNNING_MODERATE
应用程序正常运行,并且不会被杀掉。但是目前手机的内存已经有点低了. - TRIM_MEMORY_RUNNING_LOW
表示应用程序正常运行,并且不会被杀掉。但是目前手机的内存已经非常低了,我们应该去释放掉一些不必要的资源以提升系统的性能,同时这也会直接影响到我们应用程序的性能。 - TRIM_MEMORY_RUNNING_CRITICAL
表示应用程序仍然正常运行,但是系统已经根据LRU缓存规则杀掉了大部分缓存的进程了。这个时候我们应当尽可能地去释放任何不必要的资源,不然的话系统可能会继续杀掉所有缓存中的进程,并且开始杀掉一些本来应当保持运行的进程,比如说后台运行的服务。 - TRIM_MEMORY_UI_HIDDEN
表示应用程序的所有UI界面被隐藏了,即用户点击了Home键或者Back键导致应用的UI界面不可见.这时候应该释放大量UI资源,此时APP在缓存的APP列表中,如果有问题,APP进程会被结束.
当应用程序是缓存的,也就是不在前台的时候,则会收到以下几种类型的回调:
- TRIM_MEMORY_BACKGROUND 表示手机目前内存已经很低了,系统准备开始根据LRU缓存来清理进程。这个时候我们的程序在LRU缓存列表的最近位置,是不太可能被清理掉的,但这时去释放掉一些比较容易恢复的资源能够让手机的内存变得比较充足,从而让我们的程序更长时间地保留在缓存当中,这样当用户返回我们的程序时会感觉非常顺畅,而不是经历了一次重新启动的过程。
- TRIM_MEMORY_MODERATE 表示手机目前内存已经很低了,并且我们的程序处于LRU缓存列表的中间位置,如果手机内存还得不到进一步释放的话,那么我们的程序就有被系统杀掉的风险了。
- TRIM_MEMORY_COMPLETE 表示手机目前内存已经很低了,并且我们的程序处于LRU缓存列表的最边缘位置,系统会最优先考虑杀掉我们的应用程序,在这个时候应当尽可能地把一切可以释放的东西都进行释放。
详细讲解https://www.androidperformance.com/2015/07/20/Android-Performance-Memory-onTrimMemory/
案例
- 内部类runnable未执行完,而外部类Activity已销毁导致泄露.这种情况多是内部类比外部类的生命周期要长,而内部类又持有外部类的this$0引用导致.解决办法1. 内部类声明为静态的.持有外部类的弱引用.对弱引用进行判空处理. 2. 外部类在销毁时也移除静态内部类,停止内部类的任务.
public class MainActivity extentd Activity{
onCreate(){
mHandler.postDelayed(new Runnable() { //
@Override
public void run() {
// TODO Auto-generated method stub
}
}, 60*60*1000);
}
}
- 避免内存泄露
- 需要context的地方.传入Activity.造成泄漏.context的释放时间不确定.所以应改成applicationContext
- 静态变量长期持有对象.如bitmap. --类在销毁时要去掉静态变量的引用
- 使用系统服务造成泄漏. --用application.getSystemservice代替 Activity.getSystemService
- WebView 泄漏. --把WebView设置为独立进程
- 定时器,延时器持有外部类. --这个和上边的匿名内部类是一样的, Activity销毁后移除定时器延时器
几种定时器讲解,https://www.cnblogs.com/dame/p/8085983.html,所以当我们使用handler,runnable.Timer.类和 postDelay方法时,一定要考虑持有外部类this$0引用的问题. - 资源性对象(数据库,文件,io流)在使用完没有及时关闭造成泄漏,仅仅设置为null也会泄露. 需要close.在设置为null.
- 注册的监听对象未销毁. listener,callback,register.在activity销毁时,需要及时关掉,不然会造成Activity的泄露.
- 减少内存消耗
- 图片解码使用RGB656.减少内存消耗
- 图片资源可放在 xxhdpi下,低分辨率的手机会对图片资源进行压缩显示
- 大图片通过injustDecode确定尺寸,进行缩放解码
//先得到图片的比例,在根据想要的比较计算缩放比.这样可以显示正确的图片大小,而且节省内存资源
public Bitmap decodeBitmap()
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 通过这个bitmap获取图片的宽和高
Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/MTXX/3.jpg", options);
float realWidth = options.outWidth;
float realHeight = options.outHeight;
// 计算缩放比
int scale = (int) ((realHeight > realWidth ? realHeight : realWidth) / 100);
if (scale <= 0)
{ scale = 1; }
options.inSampleSize = scale;
options.inJustDecodeBounds = false;
// 注意这次要把options.inJustDecodeBounds 设为 false,这次图片是要读取出来的。
bitmap = BitmapFactory.decodeFile("/sdcard/MTXX/3.jpg", options);
int w = bitmap.getWidth();
int h = bitmap.getHeight();
return bitmap;
- 合理使用数据接口, List<Integer> 这种是不合理的.因为 int 转Integer会造成频繁的装箱拆箱,创建对象.
- 枚举类型的开销是常量的三倍以上.也要减少使用
- 使用对象池 ,这暂时了解下吧.好像没看到哪里用过https://www.jianshu.com/p/38c5bccf892f
- bitmap使用 inBitmap复用内存. 主要就是指的复用内存块,不需要在重新给这个bitmap申请一块新的内存,避免了一次内存的分配和回收,从而改善了运行效率,glide也使用了这个技术.
技术讲解https://my.oschina.net/u/3863980/blog/3019921
https://www.jianshu.com/p/eadb0ef271b0 - 使用LRUCache.
附一篇讲LRU算法的,并抄录一段总结. LruCache中维护了一个集合LinkedHashMap,该LinkedHashMap是以访问顺序排序的。当调用put()方法时,就会在集合中添加元素,并调用trimToSize()判断缓存是否已满,如果满了就用LinkedHashMap的迭代器删除队尾元素,即近期最少访问的元素。当调用get()方法访问缓存对象时,就会调用LinkedHashMap的get()方法获得对应集合元素,同时会更新该元素到队头
https://www.jianshu.com/p/b49a111147ee
3. io优化
原理
1.随机读写问题.
- 扇区:磁盘的最小存储单位;这是物理层面的存储单位
- 块:文件系统读写数据的最小单位;这是操作系统与硬件对应的虚拟的存储单位
- 页:内存的最小存储单位; 这是操作系统与内存对应的虚拟的存储单位.
- 一个磁盘块由连续几个(2^n)扇区组成;
- 页的大小为磁盘块大小的2^n倍;
随机读写的性能比顺序读写要效率低,因为随机读写要多次切换读取数据的地址,并且会有写入放大效应,导致效率低下,写入放大效应是值要写入的数据的大小超过了当前块中连续的连续的内存,为了写入新数据,要把快中所有有用的数据全部取出,清空块的数据,再把原来数据和新数据一起写入.
写入在SSD中的数据是不可以直接更新的,只能通过扇区覆盖重写,在覆盖重写之前需要先擦除,而且擦除操作又是不能在扇区上做的,只能在磁盘的块上来完成,擦除块之前需要将原有的还有效的数据先读出,然后在与新来的数据一起写入,这些重复的操作不单会增加写入的数据量 ,还会减少闪存的寿命,更吃光闪存的可用带宽而间接影响随机写入性能。
举个最简单的例子:当要写入一个4KB的数据时,最坏的情况是一个块里已经没有干净空间了,但有无效的数据可以擦除,所以主控就把所有的数据读到缓存,擦除块,缓存里更新整个块的数据,再把新数据写回去,这个操作带来的写入放大就是: 实际写4K的数据,造成了整个块(共512KB)的写入操作,那就是放大了128倍。同时还带来了原本只需要简单一步写入4KB的操作变成:闪存读取(512KB)→缓存改(4KB)→闪存擦除(512KB)→闪存写入(512KB),共四步操作,造成延迟大大增加,速度变慢。
2.文件io问题.
案例
- sharedPreferencs每调用一次就是对应一次文件的io操作.所以只在需要时候调用就好.同时改用apply异步提交.
- 对于系统中的配置文件.读取后保存在缓存中即可.不需要重复读取
- 主线程不要进行io操作.
- 用ButeArrayStream和BufferStream代替ObjectStream.因为ObjectStream在保存对象时每个成员都会进行一次IO操作.
- inputStream/outputStream流时,用 byte buff[] =new byte[4096] .使用4kb-8kb来提升读写效率
- ZipFile用来解压本地文件效率高.他每次传递1-64kb数据给native层解压. ZipInputStream则适应边下载边解压的方式.
- 数据库减少重复开闭.在APP退出时进行close即可.
- 数据库的autoincrement 字段递增字段会额外增加插入时间.不要滥用
- bitmap适应DecodeStream不要适应decodeFile, 在4.4以上效率不高.同时给decodeStream传的文件流是bufferInputStream
- sql中频繁插入要使用事务.因为没执行一次插入操作.系统会自动创建事务,如果插入频繁,会频繁创建事务.影响效率.所以要显示的创建事务.
- 在序列化对象是使用FlatBuffers.比较高效且节省内存.json序列化效率很低.serializable会销毁额外内存,引起gc. parcelable不适应把对象持有话,他是为了进行ipc传递对象.sharedPreference只能保存简单类型,且会有线程同步锁.
附一个大神的博客. 性能优化合集.很全面
https://www.jianshu.com/p/ab057549c582
4. 网络优化
原理
1.业务成功率
业务成功率就是保证网络接口能正常通信,这里通常问题有两个.
- 弱信号网络(走进电梯后的情况),解决办法就是APP里进行接口重试,这种弱信号通常都是短时间的.
- 拥塞网络
计算机网络中的带宽、交换节点中的缓存和处理机等,都是网络的资源,在某段时间内,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏,这种情况就叫做拥塞。简单说就是发送发同时发送的数据量超过了这条链路的承受能力.
详细文章解释https://blog.csdn.net/zhangdaisylove/article/details/47294315
解决办法是减少不重要的网络请求,减少网络重试 - 窗口分为滑动窗口和拥塞窗口。
滑动窗口是接受数据端使用的窗口大小,用来告知发送端接收端的缓存大小,以此可以控制发送端发送数据的大小,从而达到流量控制的目的,如果传输稳定,滑动窗口会变大来增加发送效率.当网络不好时会降低滑动窗口的大小.滑动窗口其实就是接收方可以承受的数据流入大小.
拥塞窗口是数据的发送端,拥塞窗口不代表缓存,拥塞窗口指某一源端数据流在一个RTT内可以最多发送的[数据包]数,拥塞窗口是为了提高在链路上发送的效率问题.接收方告诉发送方滑动窗口的大小.但是发送端并不知道网络是否可以正常支持滑动窗口大小的数据,所以就先发一个包.拿到应答后.在发两个包.在三个包.逐渐增大发送包的数量.这样就减少了网络拥塞
https://juejin.im/post/5c9f1dd651882567b4339bce
2. 网络延时
1.dns解析慢, 通过域名查找IP的过程.dns会按照本地缓存-操作系统缓存-路由器缓存-ISP DNS 缓存服务器-迭代查询来逐步查找域名对应的IP地址,在那里找到就返回给用户.所以这个也是耗时的过程.
2.建立链接,TCP需要三次握手,用来确认通信双方都能接受到数据.这里也是耗时的.可以通过建立长连接来减少三次握手的耗时.
3.接收窗口.用于拥塞控制.果在发送方和接收方之间存在多个路由器和速率较慢的链路,那么开始时就要发送少量数据.然后慢慢增加数据发送量.随着时间的推移增加发送量. 这个可以调节到合适的接受窗口大小.
3. 带宽成本
减少流量的浪费.也是节省带宽和资源的方式.常用的有对资源进行压缩.对进行增量更新数据,去除重复下载的数据.
图片可以采用 WebP压缩,PNG压缩.文本用gzip来压缩.
案例
- webview设置缓存
- 网络资源(图片,文本.HTML)进行压缩
- 调大服务器的滑动窗口来提高上传速度
- 设置请求响应头来来进行缓存
- 减少网络连接,使用jobScheduler进行同步`
- 监测网络状态
5. 电量优化
原理
- 正常情况下,社保在活动状态下使用1秒的耗电量相当于待机2分钟的耗电量.
- doze模式
激活状态, 屏幕点亮
休眠状态,屏幕休眠,社社保处于唤醒状态(30分钟)
待闲置状态,准备进入闲置状态(30分钟)
闲置状态, 社保休眠
闲置维护状态,队列中的alarm和更新任务短暂的执行的机会
设备用30分钟从休眠到待闲置,在用30分钟进入闲置状态.进入闲置状态后.设备推迟所以alarm到下一个闲置维护期,这个延时不断增加(1.2.3.6)小时.
详解连接 https://chendongqi.me/2017/02/28/pm_doze_MeetDoze/
doze模式有哪些限制
–网络连接会被禁止
–Wake Lock会被屏蔽
–AlarmManager定时任务延迟到下一个maintenance window进行处理,除非使用AlarmManager提供的方法:setAndAllowWhileIdle()或者setExactAndAllowWhileIdle()
–系统将不扫描热点WIFI
–同步工作将被禁止
–不允许JobScheduler进行任务调度
案例
1. alarmManager
AlarmManager aManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent in = new Intent();
in.setClass(context, RebootService.class);
PendingIntent pi = PendingIntent.getService(context, 0, in, 0);
aManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,24 * 60 * 60 * 1000, pi);
记录几个详解文章
https://juejin.im/entry/588628e8128fe10065eb62a9
https://www.jianshu.com/p/32f438a0c239
https://blog.csdn.net/u012527802/article/details/70230110
2. WakeLock
WakeLock是Android框架层提供的一套机制,应用使用该机制可以达到控制Android设备状态的目的。这里的设备状态主要指屏幕的打开关闭,cpu的保持运行。简单的理解WakeLock是让系统保持"清醒"的一种手段
PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK
| PowerManager.ON_AFTER_RELEASE,TAG);
wl.acquire();//为了保证任务不被系统休眠打断,申请WakeLock
// 开始我们的任务
wl.release();//任务结束后释放,如果不写该句。则可以用wl.acquire(timeout)的方式把释放的工作交给系统。
讲解https://www.jianshu.com/p/67ccdac38271
3. jobScheduler
google在全新一代操作系统上,采取了Job (jobservice & JobInfo)的方式,即每个需要后台的业务处理为一个job,通过系统管理job,来提高资源的利用率,从而提高性能,节省电源
Job Scheduler是将多个任务打包在一个场景下执行,当条件满足时采取执行.
使用过程讲解https://www.jianshu.com/p/55e16941bfbd
使用过程讲解 https://www.jianshu.com/p/9fb882cae239
源码讲解http://gityuan.com/2017/03/10/job_scheduler_service/
4. SyncAdapter
SyncAdapter是一个系统服务,通过系统的定时器更新应用程序数据ContentProvider,因为sync服务工作在独立进程,并且有操作系统歹毒,进程属于核心级别,系统不会杀掉,而使用了SyncAdapter的进程优先级本身也会提高,从而降低应用进程被杀的概率,
https://www.jianshu.com/p/dc9a2693478e
https://invoker.me/android-sync-adapter/