App后台保活调研


1. 内存优化角度

App的状态

Not running
App没有被加载,或者被系统终止

Inactive

App在前台运行,但是不接受任何事件,这个状态只有当App切换状态的过程中出现。

Active

App在前台运行,并可接受事件,通常状态下的App在前台运行时的状态。

Background

App在后台运行,并且正在执行代码.多数的App在状态切换为suspended的过程中,会在该状态下短暂停留。当App申请额外的后台执行时间时,会在该状态下多停留一会儿。另外,App推入后台时,会直接切换到该状态,而不是Inactive。

Suspended

App在后台运行,但是未在执行任何代码。切换到该状态时,系统不会通知App。该状态下,app会保留在内存中,但是不执行任何代码。当内存紧张时,系统会清理该状态下的app,以便为正在处于前台的应用使用更多的内存空间,并且没有任何通知。

以下是官方示意图:

AppDelegate代理方法:
application:willFinishLaunchingWithOptions:
application:didFinishLaunchingWithOptions:
applicationDidBecomeActive:
applicationWillResignActive:
applicationDidEnterBackground:
applicationWillEnterForeground:
applicationWillTerminate:—Lets you know that your app is being terminated. This method is not called if your app is suspended.

https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW1

系统KillApp的规则

Every app should free up as much memory as is practical upon entering the background. The system tries to keep as many apps in memory at the same time as it can, but when memory runs low it terminates suspended apps to reclaim that memory. Apps that consume large amounts of memory while in the background are the first apps to be terminated.

系统优先杀掉内存占用多的App。

Release shared system resources. The foreground app has priority for using shared services like the camera or system databases. At the time when an app would be suspended, if the app is holding any shared resources, the system terminates it instead.

当app被挂起时,未释放系统共享资源,如相机,系统数据库等,App处于系统会直接终止程序。

网上有人在后台播放静音音乐。这种情况下,当用户锁屏时,会有播放器显示出来。是一种比较流氓的做法。
想在内存层面上,解决这些问题,苹果给了一些建议,如下:

Practically speaking, your app should remove strong references to objects as soon as they are no longer needed. Removing strong references gives the compiler the ability to release the objects right away so that the corresponding memory can be reclaimed. However, if you want to cache some objects to improve performance, you can wait until the app transitions to the background before removing references to them.

Some examples of objects that you should remove strong references to as soon as possible include:

  • Image objects you created. (Some methods of UIImage return images whose underlying image data is purged automatically by the system. For more information, see the discussion in the overview of UIImage Class Reference. )
  • Large media or data files that you can load again from disk
  • Any other objects that your app does not need and can recreate easily later
    To help reduce your app’s memory footprint, the system automatically purges some data allocated on behalf of your app when your app moves to the background.

The system purges the backing store for all Core Animation layers. This effort does not remove your app’s layer objects from memory, nor does it change the current layer properties. It simply prevents the contents of those layers from appearing onscreen, which given that the app is in the background should not happen anyway.
It removes any system references to cached images.
It removes strong references to some other system-managed data caches.

去除不需要的强引用

  • 图片对象(有些返回UIImage的方法,系统会自动清除)。
  • 可以重新从磁盘获取的大文件
  • 可以很容易重新创建的对象
    此工作不会从内存中删除应用程序的图层对象,也不会更改当前图层属性。 它只是防止这些图层的内容出现在屏幕上。

2. 持久化存储角度

内存的优化并不能完美解决,App被杀掉的问题。用户开启的App越多,硬件资源就越紧张,即使App占用的内存再小,也有可能被系统杀掉。

所以苹果提供了一套,可以保存当前App状态的一套API。理论上可以完全解决,App被系统强杀后,再一次启动时,界面无法还原的问题。

The Preservation and Restoration Process

Flow of the Preservation Process

苹果官方示例

UIKit会向Appdelegate询问,是否要保存当前App状态。
查看ViewController/View是否有restorationIdentifier/restorationClass。
如果存在则调用encodeRestorableStateWithCoder:方法。
系统会将这些信息进行本地磁盘上的保存。

Flow of the Restoration Process

苹果官方示例

当App启动时,UIKit会在 application:willFinishLaunchingWithOptions:- (BOOL)application:didFinishLaunchingWithOptions:之间加上恢复App的逻辑。

  1. UIKit会向Appdelegate询问,是否要恢复App状态。
  2. 调用restorationClass 的 viewControllerWithRestorationIdentifierPath:coder:
  3. 调用viewControllerWithRestorationIdentifierPath:coder:返回ViewController的decodeRestorableStateWithCoder:

以下是苹果官方示例

苹果官方示例

如图所示,如果想存储NavigationController的TopViewController,就需要将父子链上的所有控制器都设置restorationIdentifier,才能保证下次启动时控制器的从属关系的准确性。App只能保存到这条链断开的位置。

相关API说明:

-application:shouldRestoreApplicationState:
是否要复原

-application:shouldSaveApplicationState:
是否要保存app状态

-application:willEncodeRestorableStateWithCoder:
即将复原

-application:didDecodeRestorableStateWithCoder:
复原完成

-application:viewControllerWithRestorationIdentifierPath:coder:

+viewControllerWithRestorationIdentifierPath:coder:
当viewcontroller指定restorationClass时,会调用对应class的该方法

-encodeRestorableStateWithCoder:
对需要保存的信息进行编码
ViewController 不会自动将childViewController进行保存,需要手动调用encodeObject:forKey:这会触发childViewController的encodeRestorableStateWithCoder:

-decodeRestorableStateWithCoder:
对保存的信息进行解码,复原保存的信息。
对于childViewController 需要调用decodeObjectForKey:这时会触发childViewController的decodeRestorableStateWithCoder:

特别说明:
app复原时,并不会复原viewcontroller之间的关系,UINavigationController能复原的原因是它在decodeRestorableStateWithCoder中已经处理的viewcontroller之间的关系。

App复原的步骤如下:

  • 询问viewcontroller的restoration class,并调用viewControllerWithRestorationIdentifierPath:coder:如果返回nil,UIKit会将停止创建viewController

  • 询问AppDelegate。 如果viewcontroller 没有设置 retoration class, UIkit会调用 appdelegate的application:viewControllerWithRestorationIdentifierPath:coder:。如果返回nil,则UIKit会继续查找。

  • 检查已存在的对象。UIKit会查找已经被创建的viewcontroller,前提是路径必须一致。

当强制退出app时,系统将自动删除保存的信息。

You Might Also Like
发表评论