代码之家  ›  专栏  ›  技术社区  ›  daydr3amer

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

  •  0
  • daydr3amer  · 技术社区  · 9 年前

    我的应用程序通过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 从不调用,循环将永远运行。

    1 回复  |  直到 9 年前
        1
  •  3
  •   Marcus Adams    9 年前

    你不应该循环,因为你的应用程序在iOS停止之前只需要很长时间才能处理。相反,当你的应用程序进入后台时,设置一个状态变量,使其处于后台。对前景执行同样的操作。

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

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

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