Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 643|回复: 0

iOS开发之解决应用进入后台后计时器和位置更新停止的问题

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-4-13 22:05:53 | 显示全部楼层 |阅读模式

      由于iOS系统为“伪后台”运行模式,当按下HOME键时,如程序不做任何操作,应用会有5秒的执行缓冲时间,随机程序被挂起,所有任务终端,包括计时器和位置更新等操作,但程序打开后台模式开关后,部分任务可以再后台执行,如音频,定位,蓝牙,下载,VOIP,即便如此,程序的后台运行最多可以延长594秒(大概是10分钟)。不幸的是,程序在声明后台模式后很有可能在app上架时被拒。基于此,我研究出了不用申明后台模式就能让计时器和定位在app进入前台时继续运行的方法。

      实现原理如下:

      利用iOS的通知机制,在程序进入后台和再次回到前台时发送通知,并记录进入后台的当前时间和再次回到前台的当前时间,算出两者的时间间隔,在程序任何需要的地方添加通知监听者,在监听方法中执行代码块,代码块内参数为通知对象和计算出的时间间隔。以计时器为例,程序再进入后台后,计时器停止运行,此时运用上述方法,在程序再次回到前台时执行代码块中内容,将程序进入后台时计时器的当前时间间隔加上代码块的时间间隔参数就能使计时器准确无误地计时。废话不多说,上代码:

    在AppDelegate.m实现文件中:

    - (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.
        [[NSNotificationCenter defaultCenter]postNotificationName:UIApplicationDidEnterBackgroundNotification object:nil]; } - (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.
        [[NSNotificationCenter defaultCenter]postNotificationName:UIApplicationWillEnterForegroundNotification object:nil]; }

    代码说明:程序进入后台后,利用系统通知机制通知程序进入后台和再次回到前台,监听对象为所有对象。

    之后定义一个处理程序进入后台的类YTHandlerEnterBackground

    //
    // YTHandlerEnterBackground.h // 分时租赁 //
    // Created by 柯其谱 on 17/2/24. // Copyright © 2017年 柯其谱. All rights reserved. // 
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    
    /** 进入后台block typedef */ typedef void(^YTHandlerEnterBackgroundBlock)(NSNotification * _Nonnull note, NSTimeInterval stayBackgroundTime); /** 处理进入后台并计算留在后台时间间隔类 */
    @interface YTHandlerEnterBackground : NSObject /** 添加观察者并处理后台 */
    + (void)addObserverUsingBlock:(nullable YTHandlerEnterBackgroundBlock)block; /** 移除后台观察者 */
    + (void)removeNotificationObserver:(nullable id)observer; @end

    在YTHandlerEnterBackground.m实现文件中:

     

    //
    // YTHandlerEnterBackground.m // 分时租赁 //
    // Created by 柯其谱 on 17/2/24. // Copyright © 2017年 柯其谱. All rights reserved. // 
    #import "YTHandlerEnterBackground.h"
    
    @implementation YTHandlerEnterBackground + (void)addObserverUsingBlock:(YTHandlerEnterBackgroundBlock)block { __block CFAbsoluteTime enterBackgroundTime; [[NSNotificationCenter defaultCenter]addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { if (![note.object isKindOfClass:[UIApplication class]]) { enterBackgroundTime = CFAbsoluteTimeGetCurrent(); } }]; __block CFAbsoluteTime enterForegroundTime; [[NSNotificationCenter defaultCenter]addObserverForName:UIApplicationWillEnterForegroundNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { if (![note.object isKindOfClass:[UIApplication class]]) { enterForegroundTime = CFAbsoluteTimeGetCurrent(); CFAbsoluteTime timeInterval = enterForegroundTime-enterBackgroundTime; block? block(note, timeInterval): nil; } }]; } + (void)removeNotificationObserver:(id)observer { if (!observer) { return; } [[NSNotificationCenter defaultCenter]removeObserver:observer name:UIApplicationDidEnterBackgroundNotification object:nil]; [[NSNotificationCenter defaultCenter]removeObserver:observer name:UIApplicationWillEnterForegroundNotification object:nil]; } @end

     

    该类实现了用来添加通知监听者并处理后台和移除通知监听者的方法,需要注意的是,在addObserverUsingBlock方法中,必须有if (![note.object isKindOfClass:[UIApplication class]])的判断,否则addObserverForName方法中的代码块会执行多次,此代码执行了两次。addObserverUsingBlock方法是在viewWillAppear方法中调用添加通知监听者,在viewWillDisappear方法中调用移除通知监听者。

     

    例如,在使用了计时器NSTimer控制器中:

    - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [YTHandlerEnterBackground addObserverUsingBlock:^(NSNotification * _Nonnull note, NSTimeInterval stayBackgroundTime) { self.rentTimerInterval = self.rentTimerInterval-stayBackgroundTime; }]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [self.timer invalidate]; [YTHandlerEnterBackground removeNotificationObserver:self]; }

    我定义了一个倒计时5分钟的计时器对象timer属性,并定义了一个计时器当前倒计时时间间隔rentTimerInterval属性,在添加通知监听者代码块中,rentTimerInterval等于进入后台时的倒计时时间间隔减去程序停留在后台的时间间隔,当计时器再次回到前台时,计时器此时的时间间隔是持续的。虽然计时器并未在后台持续运行,但是使用了此方法,同样实现了计时器的正确即时。

     

    同样的,当程序存在位置更新功能时,当程序进入后台,位置服务对象会自动停止更新,此时的作法依然是调用上述两个处理进入后台的方法,使得程序进入后台后,再次开始定位:

    在需要位置更新的类中:

     

    - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.locService.delegate = self; [self.locService startUserLocationService]; //进入后台再进入前台重新开始定位
        [YTHandlerEnterBackground addObserverUsingBlock:^(NSNotification * _Nonnull note, NSTimeInterval stayBackgroundTime) { [self.locService startUserLocationService]; }]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; //停止定位
        self.locService.delegate = nil; [self.locService stopUserLocationService]; //移除后台监听
     [YTHandlerEnterBackground removeNotificationObserver:self]; }

    此处使用的是百度地图SDK

     

    利用这种方法,像是计时器和位置更新等需要在后台运行的任务都可以实现相应的需求,只是麻烦的是,在任何需要的类中都要调用这两种方法,你可以根据自己的需求,在程序进入后台和再次回到前台时添加别的参数(通知对象参数是必须的),例如保存进入后台前的操作等等。或是定义不同的添加通知监听者的方法以实现不同的需求。

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-15 05:07 , Processed in 0.067068 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表