2012-08-23 55 views
4

我們目前正在開發一個iOS應用程序需要在後臺檢查位置。起初,我們試圖使用顯着的位置變化,但它們不夠準確/不經常觸發。我們考慮過使用區域監控,但是從我在線閱讀的內容來看,這並不總是準確的,而且您還有一個監控區域數量有限的問題。 (我們最終可能會嘗試區域監控)。但是,目前我們正試圖使用​​標準位置更新來跟蹤用戶在後臺的位置,並計劃每隔5分鐘檢查一次。後臺任務似乎並沒有被取消/結束

的應用程序註冊爲位置更新在後臺(使用「應用程序註冊了位置更新」爲「所需的背景模式」),和我們啓動一個後臺任務,一次檢查位置,停止位置更新,然後使用NSThread sleepForTimeInterval:到(目前,我們正在開發中)暫停任務10秒。然後,它再次檢查位置,停止位置更新,暫停10秒,等

這似乎按預期方式工作......當應用程序進入後臺,我們收到日誌/通知我們的位置更新每10秒鐘一次,當應用程序重新打開時,日誌/通知將停止。然而,問題是,當應用程序第二次進入後臺時,似乎原始後臺任務從未取消,並且創建了新的後臺任務,因此現在有兩個任務正在運行,每個檢查位置都在10秒間隔。如果應用程序被多次打開/發送到後臺,則會爲每個應用程序啓動後臺任務。

我想過設置一個標誌來說「應用程序已經被髮送到背景至少一次了?」,並且只在第一次發送到後臺時才運行該任務,但這似乎會導致其他問題,(作爲一個相對較新的iOS開發人員),我很好奇爲什麼後臺任務在應用程序進入前臺時未被取消。

的AppDelegate.h文件包含...

@interface AppDelegate : UIResponder <UIApplicationDelegate, CLLocationManagerDelegate> { 
    UIWindow *window; 
    UINavigationController *navigationController; 

    UIBackgroundTaskIdentifier bgTask; 
    BOOL inBackground; 
} 

的AppDelegate.m文件包含...

- (void)applicationDidEnterBackground:(UIApplication *)application { 
    inBackground = YES; 

    bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ 
     [[UIApplication sharedApplication] endBackgroundTask:bgTask]; 
     bgTask = UIBackgroundTaskInvalid; 
    }]; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     while (inBackground == YES) { 
      NSLog(@"%@", @"Check location..."); 
      [locationManager startUpdatingLocation]; 

      [NSThread sleepForTimeInterval:10]; 
     } 

     [[UIApplication sharedApplication] endBackgroundTask:bgTask]; 
     bgTask = UIBackgroundTaskInvalid; 
    }); 
} 

- (void)applicationWillEnterForeground:(UIApplication *)application 
{ 
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 
    inBackground = NO; 

    [[UIApplication sharedApplication] endBackgroundTask:bgTask]; 
    bgTask = UIBackgroundTaskInvalid; 
} 

更新是否按預期工作的位置,我只是不能工作爲什麼當應用程序進入前臺時後臺任務沒有被取消/結束。我想知道這與NSThread sleepForTimeInterval:有什麼關係,但我不確定它是否是,或者如何解決(如果的確如此)。預先感謝您的幫助!

+0

您應該將UIBackgroundMode添加到您的info.plist文件中,並將您的應用程序標識爲背景位置應用程序。 – J2theC

+0

謝謝,J2theC,但是我們已經爲'所需的背景模式'設置了'位置更新的應用寄存器'。 (我會編輯問題以清楚地說明這一點)。位置更新應該是他們應該做的,只是這個永無止境的後臺任務就是問題所在。 – dvyio

+1

我很確定你的實例變量'bgTask'在應用程序回到前臺時被重新分配,所以這個值不包含你想要殺死的標識符。考慮將這個標識符保存在'NSUserDefaults'中,或者更長一些。 – Hyperbole

回答

1

我相當肯定你的實例變量bgTask正在被重新分配,當應用程序回到前臺時,所以這個值不包含你想要殺死的標識符。考慮將此標識符保存在NSUserDefaults或稍微更長的一些,稍後再檢索。

+0

謝謝!我在' - (void)applicationWillEnterForeground:(UIApplication *)application'中註釋了'bgTask = UIBackgroundTaskInvalid',並且還在' - (void)applicationDidEnterBackground:(UIApplication *)application'中添加了一個if/else, bgTask'存在。現在只創建一個新的'bgTask',如果它不存在,現在它似乎工作!你認爲這是一個合理的解決方案嗎?看起來'bgTask = UIBackgroundTaskInvalid'導致了一個問題,但是我認爲這意味着在那裏。 – dvyio

+0

將值設置爲'UIBackgroundTaskInvalid'是您在完成標識符後應該執行的操作。我不明白你在評論中描述的是什麼,你能否用你到達的代碼更新你的答案? – Hyperbole

2

你不睡覺,然後要求他們管理位置更新。您可以通過在UIBackgroundMode設置「位置」(如你這樣做),然後實施CLLocationManagerDelegate管理位置更新。這與beginBackgroundTaskWithExpirationHandler:無關。這是爲了請求額外的時間(最多約10分鐘)來完成給定的操作。你不應該只是爲了獲取位置更新而調用它。

一旦你在UIBackgroundMode註冊爲一個位置的應用程序,你會自動得到更新,每當你的位置管理器中指定的精度範圍內的位置變化。系統將爲您完成所有工作。


你描述實際上可能損害電池的壽命,因爲它挫敗操作系統的管理多個位置傳感器(其中的GPS是其中一個)的能力。通過設置正確的準確度(如果重大更改過於粗糙),告訴操作系統您需要什麼,並讓它完成工作。從GPS獲取真正準確的位置非常昂貴。在假定每5分鐘更便宜的情況下,您應該進行電池測試,然後再開始測試。你可以做的最好的事情是保持力量,以降低所需的精度。你可以把它降到一個粗糙的水平,然後當你來到前臺時,把它移到一個準確的水平。但保持跟蹤精確地,其中用戶每5分鐘將是昂貴的。這很難解決。

順便說一句,你真正想要做的就是每5分鐘運行一次「東西」。 iOS中沒有這種機制。您可以要求提供位置服務或不要(並以各種方式配置它)。你不能要求「我想每五分鐘醒來......並且做任何事情。」大約10分鐘後,如果你不打電話給endBackgroundTask:,你將會被殺。

要回答爲什麼這些任務未被取消的問題,請參閱How to use beginBackgroundTaskWithExpirationHandler for already running task in iOS。正如我所說,這個「後臺任務」不是你想要解決這個問題的工具。這完全不相關。

+0

謝謝,羅布。這是我們最初嘗試的,但我們不需要不斷的位置更新。我們只需每隔x分鐘就需要一個位置,同時仍然試圖保存用戶的電池。如果重要的位置變化或區域監測更準確,那麼它們將是完美的,但我們需要比目前提供的更高的準確性。通過每隔x分鐘檢查一次位置(使用'CLLocationManagerDelegate'),然後立即關閉位置更新(直到下一次檢查),我們可以在沒有持續更新的情況下獲得準確的位置。我想,它目前正在按照希望工作。 – dvyio

+0

正如你所建議的那樣,我一定會嘗試降低準確性的標準位置更新。理想情況下,我們每30分鐘只需要一個用戶的位置,但很明顯,目前還不可能。如果有一個像重要的位置變化一樣工作的API,那將是非常好的,但是在每移動100米(或左右)之後始終提供更新。請注意,如果您正在運行後臺任務,則在該後臺任務中請求位置更新時,該後臺任務的剩餘時間將被重置。 – dvyio

+0

如果你已經設置「位置」,那麼你不應該在任何情況下被殺死。你不應該需要backgroundTask。如果你只需要100m的精度,那麼設置kCLLocationAccuracyHundredMeters。如果你想要高準確度,但不想經常打電話,這不會有助於延長電池壽命。打電話給你很便宜。跟蹤準確的位置是很昂貴的。如果您需要「有時」準確性,您可以設置kCLLocationAccuracyHundredMeters並進入後臺。當你醒來時,檢查準確性。然後設置kCLLocationAccuracyBest。如果您以更高的準確度再次醒來,請使用它。 –