一個應用程序的生命周期分為好多種狀態(tài):應用程序失去焦點身冬、應用程序完全獲取焦點、應用程序進入前臺岔乔、應用程序進入后臺酥筝、應用程序關(guān)閉、應用程序被掛起等等雏门。我們簡單說一下嘿歌,應用的前臺狀態(tài)、后臺狀態(tài)以及掛起狀態(tài)茁影。
前臺狀態(tài):但應用程序處于屏幕的第一層宙帝,呈現(xiàn)顯示的時候,就屬于前臺狀態(tài)募闲。
后臺狀態(tài):當前app如果不是作為屏幕中的第一層步脓,呈現(xiàn)顯示給用戶,那么此時app就是后臺狀態(tài)浩螺。
舉例:
鎖屏(包括:當前應用下鎖屏靴患、其他應用下鎖屏、桌面鎖屏)
用戶在使用其他應用app2要出,當前 app1 雖然沒有上滑kill掉鸳君,但是屏幕中的第一層顯示的是app2, 那么app1就是后臺了。
ps:下拉系統(tǒng)菜單 厨幻、上拉系統(tǒng)菜單相嵌,app并沒有進入后臺狀態(tài),只不過app失去了焦點罷了况脆。
掛起狀態(tài):當前app后臺狀態(tài)饭宾,但是不一定掛起,掛起就是關(guān)于app的一切代碼都不再運行了格了。
從測試實踐來看看铆,如果app進入后臺狀態(tài),一般情況下是很快就會被掛起的盛末,也就是進入后臺狀態(tài)后弹惦,里面代碼運行馬上就停止了。
如果需要在app進入到后臺的時候悄但,仍要繼續(xù)運行棠隐,需要怎么辦呢?
兩種情況:
1檐嚣、app進入后臺之后助泽,需要一兩分鐘繼續(xù)一些特殊的操作,特殊操作完成之后才會被掛起。比如:app進入后臺之后嗡贺,上傳用戶使用的操作信息隐解。
2、app進入后臺之后诫睬,需要一直保持運行煞茫。比如:后臺播放音樂。
一摄凡、創(chuàng)建后臺運行任務(app會被延時掛起3分鐘左右)
創(chuàng)建后臺運行任務之后续徽,app并不會被直接掛起,app會繼續(xù)運行到該任務的結(jié)束時間架谎,通過測試炸宵,該任務運行時間大約不到3分鐘,也就175秒左右谷扣。(不過土全,這些時間對于一些簡單的操作,也是足夠了)
例:app進入后臺之后会涎,需要上傳用戶操作數(shù)據(jù)裹匙,上傳完成之后,再讓app掛起末秃。
1概页、定義一個UIBackgroundTaskIdentifier屬性,用于記錄后臺任務的id
@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier;
2练慕、在-application:didFinishLaunchingWithOptions:方法中聲明backgroundTaskIdentifier無效惰匙。
// 首先初始化backgroundTaskIdentifier
// 應用程序啟動完成的時候就會調(diào)用AppDelegate的方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
NSLog(@"%s",__func__);
// 初始化backgroundTaskIdentifier
self.backgroundTaskIdentifier = UIBackgroundTaskInvalid;
return YES;
}
3、在-applicationDidEnterBackground:方法中創(chuàng)建后臺任務
// 當應用程序進入后臺的時候調(diào)用
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(@"%s",__func__);
// 進入后臺铃将。若沒有后臺任務项鬼,創(chuàng)建后臺任務。(如果有后臺任務劲阎,不再創(chuàng)建后臺任務)
if (self.backgroundTaskIdentifier == UIBackgroundTaskInvalid) {
// 但應用進入后臺時绘盟,要求將用戶的操作數(shù)據(jù)上傳到服務器
// 因為是上傳用戶數(shù)據(jù),不要求特別精確悯仙。
// 在本地記錄上次上傳的時候龄毡,如果兩次上傳時間不超過10分鐘,則不需要上傳锡垄。超過10分鐘沦零,才會上傳。
NSInteger lastDate = [[[NSUserDefaults standardUserDefaults] valueForKey:@"loadingDate"] integerValue];
NSInteger nowDate = (NSInteger)[[NSDate date] timeIntervalSince1970];
if (nowDate - lastDate > 600) {
// 超過了10分鐘货岭,上傳
// 標記一個長時間運行的后臺任務將開始
// 通過調(diào)試路操,發(fā)現(xiàn)序攘,iOS給了我們額外的3分鐘(180s)來執(zhí)行這個任務。
// beginBackgroundTaskWithExpirationHandler一定要和endBackgroundTask方法對應才行寻拂。
self.backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{
// 后臺任務到時間之后,會自動執(zhí)行該回調(diào)丈牢。
// 在該回調(diào)中要執(zhí)行結(jié)束后臺任務方法动漾。
// 如果操作提前完成辉饱,也可以手動結(jié)束后臺任務。如果,手動結(jié)束后臺任務绵载,則不走改回調(diào)方法。
[self endBackgroundTask];
}];
// 上傳用戶操作數(shù)據(jù)
[self uploadUserActionDataWithFinished:^(NSInteger status) {
if (status == 1) {
// 上傳用戶操作數(shù)據(jù)成功
// 刪除存儲的用戶操作數(shù)據(jù)
// 記錄最新的用戶操作數(shù)據(jù)上傳時間
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInteger:nowDate] forKey:@"loadingDate"];
[[NSUserDefaults standardUserDefaults] synchronize];
// 最后結(jié)束后臺任務
} else {
// 上傳用戶操作數(shù)據(jù)失敗胶惰,不做任何操作鹉戚,直接結(jié)束后臺任務就行
}
// 結(jié)束后臺任務
[self endBackgroundTask];
}];
} else {
}
}
}
// 結(jié)束后臺任務
- (void)endBackgroundTask {
if (self.backgroundTaskIdentifier != UIBackgroundTaskInvalid) {
// 每個對 beginBackgroundTaskWithExpirationHandler:方法的調(diào)用,必須要相應的調(diào)用 endBackgroundTask:方法。這樣师幕,來告訴應用程序你已經(jīng)執(zhí)行完成了粟按。
// 也就是說,我們向 iOS 要更多時間來完成一個任務,那么我們必須告訴 iOS 你什么時候能完成那個任務。
// 也就是要告訴應用程序:“好借好還”嘛霹粥。
// 標記指定的后臺任務完成
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier];
// 銷毀后臺任務標識符
self.backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}
}
// 上傳用戶操作數(shù)據(jù)
- (void)uploadUserActionDataWithFinished:(void (^)(NSInteger status))finish {
// 上傳用戶操作
// 這里寫了一個定時灭将,30秒以后上傳完成,結(jié)束后臺任務
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(30 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (finish) {
finish(1);
}
});
}
PS:每個對 beginBackgroundTaskWithExpirationHandler:方法的調(diào)用,必須要相應的調(diào)用 endBackgroundTask:方法后控。這樣庙曙,來告訴應用程序你已經(jīng)執(zhí)行完成了。