最近项目中有些地方需要对程序是运行在前台还是后台,应用程序各个状态的变换时做相应的处理,现在对这部分做一下梳理。因为系统的资源是有限的,程序在前台和后台的状态是不一样的,在后台时,我们需要对一些资源释放。
首先回忆一下应用程序的状态:
1.应用程序的状态
Not running 未运行 程序没有启动
Inactive 未激活 程序在前台运行,没有接收到事件。在没有事件处理情况下程序通常停留在这个状态
Active 激活 程序前台运行而且接收到事件。
Background 后台 程序在后台且能执行代码。大多数程序进入这个状态会在这个状态停留一会,时间到了之后就会进入挂起状态(Suspended)。程序也可以经过特殊请求长期处于Background状态。
Suspended 挂起 程序在后台不执行代码。系统会自动把程序变为这个状态且不会发出通知,当程序挂起时,程序还是停留在内存中,当内存低时,系统就把挂起的程序清楚掉,为前台程序提供更多的内存。
各个程序运行状态时代理的回调:
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
应用程序启动,告诉代理进程启动但还没有进入状态保存。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
启动基本完成程序准备开始运行。
- (void)applicationDidFinishLaunching:(UIApplication*)application;
应用程序载入后执行。
- (void)applicationWillResignActive:(UIApplication *)application;
应用程序将要进入非活动状态执行,在此期间,应用程序不接收消息或者事件,比如来电话了。
- (void)applicationDidBecomeActive:(UIApplication *)application;
应用程序进入活动状态。
- (void)applicationDidEnterBackground:(UIApplication *)application;
当应用程序被推入到后台时候调用。如果要处理进入后台释放资源或者设置后台继续运行,则在这个函数里面设置即可。
- (void)applicationWillEnterForeground:(UIApplication *)application;
当应用程序从后台重新回到前台时候调用。如果程序要处理进入前台加载资源或者页面状态处理,则在这个函数里处理。
- (void)applicationWillTerminate:(UIApplication *)application;
应用生命周期终止时调用。通常用来保存数据和一些退出前的清理工作。这个需要设置UIApplicationExitsOnSuspend的键值。
2.应用程序响应中断
2.1当一个基于警告式的中断发生时,比如接入电话,这时程序临时进入Inactive状态,用户选择如何处理这个中断。
例如电话中断程序时,首先会调用applicationWillResignActive:方法,程序进入Inactive状态,处理完中断事件,会调用applicationDidBecomeActive:方法,程序进入active状态。
在iOS11.0之前,通知中断程序,会调用applicationWillResignActive:方法,当程序激活时,会调用applicationDidBecomeActive:方法。
在iOS11.0之后,中断程序,首先会调用applicationWillResignActive:方法,随后调用applicationDidBecomeActive:方法,再次调用applicationWillResignActive:方法;当程序激活时,会调用一次applicationDidBecomeActive:方法。
所以如果程序中某个页面需要单独处理进入前后台事件,调用UIApplicationDidBecomeActiveNotification通知方法时,注意判断程序是中断处理还是进入前后台处理,保证进入前后台的处理事件顺序正确。
按锁屏键也是另外一种程序中断。按锁屏键中断程序时,会先调用applicationWillResignActive:方法,进入Inactive状态,再调用applicationDidEnterBackground:方法,让程序进入后台;解锁后,会先调用applicationWillEnterForeground:方法,再调用applicationDidBecomeActive:方法进入active状态。
2.2有中断产生时,app的处理是在applicationWillResignActive:方法中:
1.停止timer和其他周期性的任务;
2.停止任何正在运行的请求;
3.减少OpenGL ES的帧率;
4.暂停视频的播放;
5.挂起任何分发的队列和不重要的操作队列;
当程序回到active状态,applicationDidBecomeActive:方法应该重新开始停止的任务。
3.应用程序转到后台运行
3.1流程图:
只有在iOS4以上系统或者支持多任务的设备才能后台运行,否则直接结束程序。
3.2当程序进入后台时,应该处理什么?
1.保存用户数据或状态信息等需要存储的内容。在进入后台时,应用程序可能在后台被杀死。
2.释放尽可能的内存,和需要释放的资源。
3.3应用程序在后台的内存使用
在后台时,应用程序都应该释放最大的内存。系统极可能保持更多的应用程序同时在后台运行。当内存不足时,会终止一些挂起的程序来回收内存,那些内存消耗最大的程序首先会终止。其实在编写代码时,如果对象不再使用,就应该尽快释放掉,编译器就可以回收这些内存。
平时,这些对象应该尽快释放:
1.图片对象;
2.可以重新加载的大视频或者数据文件;
3.任何没有用,可以重新创建的对象;
一般在后台时,为了减少程序占用的内存,系统会自动回收一些内存,如:
1.系统回收Core Animation 的后备储存;
2.去掉系统引用的缓存图片;
3.去掉系统管理数据缓存强引用;
4.应用程序返回前台运行
流程图如下:
当app处于挂起状态时,是不能执行任何代码的。因此程序不能处理在挂起期间发过来的通知,比如时间改变,方向改变,设置的改变还有其他影响程序的通知。在程序返回后台或前台时,程序都要正确的处理以上这些通知。
5.应用程序终止
程序只要符合下列情况之一,只要进入后台或挂起状态就会终止:
1.app是基于iOS4.0之前系统开发的;
2.设备不支持多任务;
3.在info.plist文件中,程序包含了UIApplicationExitsOnSuspend键;
app如果终止了,系统会调用app的代理方法applicationWillTerminate: 在这个方法中可以做一些清理或者保存数据,app状态等工作。这个方法有时间限制,超时后方法会返回程序从内存中清除。
*用户可以手工关闭应用程序。