如何使用beginBackgroundTaskWithExpirationHandler在iOS中已经运行的任务
在我的应用程序中,我从iPhone上传图像到服务器。 如果用户按Home键同步,App将closures。
我希望应用程序必须在后台运行,直到同步完成。
我的问题是:如何添加当前正在运行的任务与“ beginBackgroundTaskWithExpirationHandler
”?
请分享你的想法。
尽pipe它的名字, beginBackgroundTaskWithExpirationHandler:
实际上并不“开始”一项任务。 这可能更好地被认为是“注册…”,而不是“开始……”。你只是告诉系统,如果没有问题,你正在做一些想要完成的事情。
几点:
-
在几乎所有情况下,你都要调用
beginBackgroundTaskWithExpirationHandler:
当你开始做你想做的事情,然后endBackgroundTask:
当你完成。 在用户按下主页button的时候,你几乎不会调用它们(除非这是你开始任务的时候,比如把东西保存到服务器上)。 -
您可以一次打开许多“后台任务”。 他们不花钱。 他们就像保留计数。 只要你还有一个开放的(一个“开始”没有达到它的“结束”),那么系统会考虑这个请求更多的时间。 调用“开始”和“结束”方法的代价非常小,因此使用这些来包含任何需要额外时间完成的任何内容。
-
没有办法确定您将完成您的同步。 这些方法只是提出请求。 操作系统可能仍然拒绝该请求。 任何时候当操作系统需要一些额外的资源时,操作系统仍可能会杀死你 操作系统不是无限的耐心; 如果花费时间太长(通常约10分钟),则在呼叫过期处理程序之后无论如何都会杀了你。 操作系统可能会因为手机关机而杀了你。 你的应用程序必须能够处理不完成。 操作系统只是给你这个能力,以便你可以改善用户体验。
我将下面的代码用于后台任务处理程序:
__block UIBackgroundTaskIdentifier backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ NSLog(@"Background Time:%f",[[UIApplication sharedApplication] backgroundTimeRemaining]); [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskIdentifier]; backgroundTaskIdentifier = UIBackgroundTaskInvalid; }];
以下是我使用beginBackgroundTaskWithExpirationHandler的方法,包括调用方法在后台完成。 这包括开始新的asynchronous任务的代码。 所以不是在问题中问的是什么。 在下面添加代码,认为有人可能正在寻找这种情况:
- (void)didReceiveObjList:(CFDataRef)message { // Received Object List. Processing the list can take a few seconds. // So doing it in separate thread with expiration handler to ensure it gets some time to do the task even if the app goes to background. UIApplication *application = [UIApplication sharedApplication]; __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{ [application endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self processObjList:message]; [application endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }); NSLog(@"Main Thread proceeding..."); }
看看这个页面,苹果描述了如何让iOS应用程序在后台暂停。 Apple文档
这是我实现的:
UIBackgroundTaskIdentifier bgTask; - (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, this method is called instead of applicationWillTerminate: when the user quits. NSLog(@"=== DID ENTER BACKGROUND ==="); bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ NSLog(@"End of tolerate time. Application should be suspended now if we do not ask more 'tolerance'"); // [self askToRunMoreBackgroundTask]; This code seems to be unnecessary. I'll verify it. }]; if (bgTask == UIBackgroundTaskInvalid) { NSLog(@"This application does not support background mode"); } else { //if application supports background mode, we'll see this log. NSLog(@"Application will continue to run in background"); } } /* - (void)askToRunMoreBackgroundTask { [[UIApplication sharedApplication] endBackgroundTask:bgTask]; NSLog(@"restart background long-running task"); bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ NSLog(@"End of tolerate time. Application should be suspended now if we do not ask more 'tolerance'"); [self askToRunMoreBackgroundTask]; }]; } */ - (void)applicationWillEnterForeground:(UIApplication *)application { NSLog(@"=== GOING BACK FROM IDLE MODE ==="); //it's important to stop background task when we do not need it anymore [[UIApplication sharedApplication] endBackgroundTask:UIBackgroundTaskInvalid]; }
下面是我在应用程序进入后台时使用的其他答案的细微变化,我需要在主线程上做些事情:
- (void)applicationWillResignActive:(UIApplication *)application { UIApplication *app = [UIApplication sharedApplication]; // Register auto expiring background task __block UIBackgroundTaskIdentifier bgTaskId = [app beginBackgroundTaskWithExpirationHandler:^{ [app endBackgroundTask:bgTaskId]; bgTaskId = UIBackgroundTaskInvalid; }]; // Execute background task on the main thread dispatch_async( dispatch_get_main_queue(), ^{ // ------------------ // DO SOMETHING INVOLVING THE WEBVIEW - WHICH MUST OCCUR ON THE MAIN THREAD! // ------------------ [app endBackgroundTask:bgTaskId]; bgTaskId = UIBackgroundTaskInvalid; }); }
您应该在beginBackgroundTaskWithExpirationHandler
之后运行您的任务,或者在应用程序将状态更改为背景时捕获通知,然后取消当前的任务并使用beginBackgroundTaskWithExpirationHandler
再次运行。