结束后台任务并等待应用程序再次激活 - BLE 处理数据

End background task and wait until app becomes active again - BLE processing data

我的应用程序通过 BLE 从外围设备下载了一堆数据。如果我锁定屏幕,我的应用程序将移至后台并启动后台任务。下载完成正常,但如果处理(需要相当长的时间,因为它有很多数据)开始应用程序崩溃,因为它无法连接到数据库。

我想在那一点停止执行并等待应用程序再次激活,但不知何故我无法实现。我想我需要某种信号量来等待应用程序激活。

这里是我的代码:

- (void)viewDidLoad
{
    //Some other code

    //initialize flag        
    isInBackgroud = NO;

    // check if app is in the background
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];

    // check if app is in the foreground
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidEnterForeground) name:UIApplicationDidBecomeActiveNotification object:nil];
}

- (void)appDidEnterBackground {
    NSLog(@"appDidEnterBackground");
    isInBackground = YES;
    UIApplication *app = [UIApplication sharedApplication];
    NSLog(@"remaining Time: %f", [app backgroundTimeRemaining]);
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        NSLog(@"expirationHandler");
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];
}

- (void)appDidEnterForeground {
    NSLog(@"appDidEnterForeground");
    isInBackground = NO;
    if (bgTask != UIBackgroundTaskInvalid) {
        UIApplication *app = [UIApplication sharedApplication];
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }
}

//BLE connection and reading data via notification
//when finished [self processData] is called.

- (void)processData {
    if (isInBackground) {
        //set reminder
        UILocalNotification *localNotification = [[UILocalNotification alloc] init];
        localNotification.fireDate = [NSDate date];
        localNotification.alertBody = [NSString stringWithFormat:@"Data was downloaded, return to the application to proceed processing your data."];
        localNotification.timeZone = [NSTimeZone defaultTimeZone];
        [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
        UIApplication *app = [UIApplication sharedApplication];

        //end background task
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;

        //wait for application to become active again
        while (isInBackground) {
            NSLog(@"isInBackground");
            NSLog(@"remaining Time: %f", [app backgroundTimeRemaining]);
            sleep(1);
        }

        //process data
    }

所以我注意到如果我调用 [app endBackgroundTask:bgTask]; 应用程序会继续 运行 但是当我想连接到我的数据库时崩溃。这就是我添加 while(isInBackground) 循环的原因。我知道这不是好的做法,因为它在做笔记时会浪费 CPU 时间。那时我应该使用信号量,但我不知道该怎么做。

因为我在那个循环中积极等待,所以 appDidEnterForegronund 永远不会被调用并且循环永远运行。

您不应该循环,因为您的应用在 iOS 停止之前只需要很长时间来处理。相反,当您的应用程序进入后台时,设置它在后台的状态变量。对前景做同样的事情。

仅当您在前台时才更新数据库,否则,请设置一个状态变量,告诉您的应用程序您已完成下载,但仍需要处理数据。如果需要,请存储数据。

然后,当您的应用重新启动时,检查该变量的状态并进行处理。

与其坐在循环中等待某些状态发生变化,不如设置变量并使用事件驱动编程。