当用户按下"Home"键或者系统启动另外一个应用时,前台foreground应用首先切换到Inactive状态,然后切换到Background状态。此转换将会导致先后调用应用代理的applicationWillResignActive:和applicationDidEnterBackground:方法。
在applicationDidEnterBackground:方法返回后,大部分应用在之后不久转入suspended状态。对于请求特定后台background任务的应用,比方播放音乐应用,或者那些请求须要额外运行时间的应用,可能会继续运行更长一段时间。
注:应用从froeground切换到background仅仅有在支持多任务而且执行iOS4.0或更新版本号系统的设备上才会发生。全部其他的情况,应用不是切向后台,而是直接终止,而且从内存中清除。
应用切向后台background时应该做什么:
应用能够在applicationDidEnterBackground:方法中做些切向background状态前须要做的一些准备工作,当切向background状态时,全部的应用须要做下面事情:
(1)应用界面快照。当applicationDidEnterBackground:方法返回时,系统保存应用界面的快照,而且使用快照图片作为转换动画。假设在你的应用界面中有涉及到敏感信息的视图,则你应该在applicationDidEnterBackground:方法返回前隐藏或者改动这些视图。
(2)保存用户数据和应用状态信息。全部没有保存的改变都应该在切向background状态前写入磁盘以保存。这一步是必须的,由于你的应用在后台时非常有可能由于多种其他原因而被非常快kill掉。依据须要你能够在background
thread后台线程中运行这些操作。
(3)释放尽可能多的内存资源。
applicationDidEnterBackground:方法同意最多有5秒的时间去完毕不论什么任务然后返回。实际中,此方法应该尽可能快的返回。假设在时间到期之后,此方法没有返回,则应用即被kill掉,而且清除所占用的内存。假设你的应用确实须要很多其它的时间去运行任务,能够调用beginBackgroundTaskWithExpirationHandler:方法请求后台运行时间,然后启动一个能长期运行任务的线程。不管你是否启动一个运行后台任务的线程,applicationDidEnterBackground:方法都必须在5秒后退出。
注:UIApplicationDidEnterBackgroundNotification通知也会发送,以让应用对此通知感兴趣的部分知道当前应用正切向background状态。你的应用中的对象能够使用默认的通知中心注冊这个通知。
根据不同的应用场合,应用切向后台时还有非常多其他的事情须要做,比方active状态的Bonjour服务应该暂停,应用应该停止调用OpenGL
ES函数。
由于前台应用在使用系统资源和硬件时一直比后台应用具有更高的优先权。执行在后台的应用应该对此差异有心理准备,而且在后台执行时要调整它们的訪问资源行为。特别的,当应用切向background时尤其要遵循下面几点:
(1)不要在应用代码中调用不论什么OpenGL ES的东西。当应用在后台执行时不能够创建EAGLContext对象或者发出不论什么OpenGL
ES绘画命令,使用这些调用将会导致应用马上被kill掉。应用也必须保证先前提交发出的全部命令在应用切向background状态前都已运行完成。详细细节请參考“OpenGL ES Programming Guide for iOS”中“Implementing a Multitasking-aware OpenGL ES Application”部分。
(2)在应用挂起suspended之前取消全部Bonjour相关的服务。当应用转向后台,而且在被挂起前,应用应该unregister
Bonjour服务而且关掉不论什么和网络服务相关的sockets监听。挂起的应用是没法响应这些服务请求的。假设你的应用不关掉这些和Bonjour相关的服务,当应用被挂起的时候,系统会自己主动帮你关掉这些服务。
(3)在基于网络sockets的应用中,须要处理连接失败的情况。当你的应用由于某些原因而被挂起时,系统可能会拆除socket连接。仅仅要你的应用对尽可能多的网络错误情况都有非常好的处理,像丢掉信号等,此类问题不会导致你的应用出现不正常。当应用从后台退出恢复运行时,假设遇到sockets使用错误,简单的重建socket连接就可以。
(4)在切向background状态前保存应用状态。在低内存告警时,后台应用可能会被清除出内存以释放空间。处于suspended状态的应用被优先清除内存,而且在被清除前不会给出不论什么通知。因此,当应用切入background状态前一定要保存足够多的应用状态信息以便后面恢复时使用。
(5)当切向后台时,释放全部不再须要的内存。假设你的应用保持着一个非常大的内存缓存对象(比方图像),则切入后台前,释放全部的对这些缓存对象的引用。
(6)在被挂起前停止使用系统共享资源。使用系统共享资源(比方Address Book或Calendar
Data)的应用,在被挂起前必须停止对这些共享资源的使用。对这些资源的使用,前台应用具有更高的优先使用权,假设发现你的应用在被挂起后还没有停止对这些共享资源的使用,则应该将被kill掉。
(7)避免更新应用窗体和视图。当应用处在后台时,应用窗体和视图是不可见的,所以不须要更新它他。虽然在后台创建和操纵窗体和视图对象并不会导致应用被kill掉,可是能够考虑将这些工作推迟到应用返回前台时运行。
(8)响应外部附件连接和失去连接通知。针对和外部附件有通信的应用,当应用切向background状态时,系统会发送一个disconnection通知。应用必须注冊此通知而且使用它去关掉当前的附件訪问session。当应用返回foreground时,会有一个与之匹配的通知被发送,给应用提供又一次建立session的机会。
(9)切向后台时,清除行为警告相关的资源。为了在应用相互切换之间保存应用上下文,当应用切向后台时,系统并不自己主动dismiss
action sheets(UIActionSheet)和alert views(UIAlertView)。由应用设计者去提供具本的清除方案。对于执行在iOS4.0版本号之前的应用,在退出时action sheets和alerts仍然被dismiss掉,以让应用的取消处理函数有机会去执行。
(10)切向后台时,移除全部敏感视图信息。由于系统会快照顾用界面而且生成应用切换动画,所以带有敏感信息的视图或窗体必须隐藏或移除,详细原因前面已介绍。
(11)应用在后台执行时执行最少量化的工作。系统给后台执行的应用的执行时间和给前台执行的应用相比,通常很有限。假设应用在后台播放音频或者监測位置变化,则应用应该仅关注此任务,全部不必要的任务都应该被推迟。在后台执行时间过长的应用会被系统throttled
back或者直接被kill掉。
下来我们操作一下看看:
AppDelegate.h:
///
UIBackgroundTaskIdentifier bgTask;
NSUInteger counter;
AppDelegate.m:
- (void)backgroundHandler {
NSLog(@"### -->backgroundinghandler");
UIApplication* app = [UIApplicationsharedApplication];
bgTask = [appbeginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask =UIBackgroundTaskInvalid;
}];
// Start the long-running task
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
^{
while (1) {
NSLog(@"counter:%d",counter++);
[[UIApplicationsharedApplication]setApplicationIconBadgeNumber:numbers++];
sleep(1);
}
});
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
*/
printf("\n applicationDidEnterBackground \n");
//////////////////////////////////////
BOOL backgroundAccepted = [[UIApplicationsharedApplication]setKeepAliveTimeout:600handler:^{
[selfbackgroundHandler];
}];
if (backgroundAccepted)
{
NSLog(@"backgrounding accepted");
}
[selfbackgroundHandler];
}
info.plist:
Required background modes字段:
App provides Voice over IP services;
OK就能够看到后台程序在执行了!
步骤:
1.在info.plist里增加UIBackgroundModes键,其值为数组,数组之中的一个为voip字符串:
<key>UIBackgroundModes</key><array><string>voip</string></array>
2.在程序启动的时候调用- (void)setupBackgroundHandler函数,函数体例如以下:
#pragma
- void )setupBackgroundHandler
{
if (
{
if (
[[UIApplication
{
[ self requestServerHowManyUnreadMessages];
}
]
)
{
UDLog(@ "Set );
}
else
{ //failed
UDLog(@ "Set );
}
}
else
{
UDLog(@ "This );
}
}
- void )requestServerHowManyUnreadMessages
{
UIApplication*
if ([app
{
NSArray *
if ([oldNotifications
[app
UILocalNotification*
if (alarm)
{
alarm.fireDate NSDate dateWithTimeIntervalSinceNow:15];
alarm.timeZone NSTimeZone defaultTimeZone];
alarm.repeatInterval
alarm.soundName
alarm.alertBody "Time ;
[app
}
}
else if ([app
{
UIAlertView
[alertView "alert" ];
[alertView "Time ];
[alertView NSLocalizedString (@ "cancel" , nil )];
[alertView nil ];
[alertView
}
}
|
讲解:
- (BOOL)setKeepAliveTimeout:(NSTimeInterval)timeout handler:(void (^)(void))keepAliveHandler
函数功能:app每隔timeout唤醒一次。
0.要成功调用该函数,就必须在Info.plist里设UIBackgroundModes键的array值之中的一个voip字符串.
1.timeout必须>=600
2.唤醒app的时间间隔是不精准的。
3.唤醒后仅仅有10秒运行时间。即handler里的代码要在10秒类运行完。10秒后app再次被堵塞。
(能够用-backgroundTimeRemaining属性来返回剩余时间)
4.该函数成功调用后,在程序生命周期内有效。
该函数的效果在回到前台的状况下,依旧有效。(因此能够把它当timer使.)
5.clearKeepAliveTimeout函数用来清除handler。
代码下载:http://download.csdn.net/detail/kaitiren/7930749