停止AVPlayer并在缓存阶段立即播放其它视频闪退问题及解决方案

简介: 停止AVPlayer并在缓存阶段立即播放其它视频闪退问题及解决方案

1.清除KVO;

2.暂停;

3.清空缓存区;

4.从父视图移除播放器;

5.移除播放器的全部视图;

6.把播放器置为nil。

具体代码:


-(void)hiddenPlayer
{
    if(self.isPlay && self.player)
    {
        [self.player.currentItem  removeObserver:self forKeyPath:@"status"];
        [self.player.currentItem  removeObserver:self forKeyPath:@"loadedTimeRanges"];
        [self.player pause];
        self.currentPlayerItem = nil;
        [self.player replaceCurrentItemWithPlayerItem:nil];//清除播放缓存
        for (CALayer *layer in self.photoImageView.layer.sublayers) {
            if ([layer class] == [AVPlayerLayer class]) {
                [layer removeFromSuperlayer];
            }
        }
        [self.player removeAllSubView];
        self.photoImageView.hidden = YES;
        self.isPlay = NO;
        self.player = nil;
//                [self.playButton setImage:[UIImage imageNamed:@"播放"] forState:UIControlStateNormal];
        [self updatePlayBtn];
    }
}

相关声明:

#import <AVFoundation/AVFoundation.h>

@interface PPChooseSongHeadView()<SDCycleScrollViewDelegate>
@property (nonatomic, strong) UILabel *describeTitleLabel;
@property (nonatomic, strong) UILabel *idLabel;
@property (nonatomic, strong) SDCycleScrollView *imagesScrollView;
@property (nonatomic, strong) UIView *backgroundView;
@property (nonatomic, strong) UIImageView *photoImageView;
@property (nonatomic, strong) UIButton *playButton;
@property (nonatomic, assign) BOOL isPlay;
@property (nonatomic, strong) JCTBannerEntity *entity;
@property (nonatomic,strong)AVPlayer *player;//播放器对象
@property (nonatomic,strong)AVPlayerItem *currentPlayerItem;
@end
@interface PPChooseSongHeadView : BGBaseView

//@property (nonatomic, strong) UILabel *backLabel;
@property (nonatomic, strong) JCTProjectListEntity *model;
@property (nonatomic, strong) PPRoomCateListEntity *roomCateListEntity;

@property (nonatomic, copy) void(^endEditingBlock)(void);

- (instancetype)initWithFrame:(CGRect)frame;

-(void)hiddenPlayer;

@end

视频建立与播放,按钮显示相关代码:

//2.添加属性观察
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {
//    AVPlayerItem *playerItem = (AVPlayerItem *)object;
    if ([keyPath isEqualToString:@"status"]) {
        //获取playerItem的status属性最新的状态
        AVPlayerStatus status = [[change objectForKey:@"new"] intValue];
        switch (status) {
            case AVPlayerStatusReadyToPlay:{
//                //获取视频长度
//                CMTime duration = playerItem.duration;
//                //更新显示:视频总时长(自定义方法显示时间的格式)
//                self.totalNeedPlayTimeLabel.text = [self formatTimeWithTimeInterVal:CMTimeGetSeconds(duration)];
//                //开启滑块的滑动功能
//                self.sliderView.enabled = YES;
//                //关闭加载Loading提示
//                [self showaAtivityInDicatorView:NO];
                //开始播放视频
                [self.player play];
                break;
            }
            case AVPlayerStatusFailed:{//视频加载失败,点击重新加载
//                [self showaAtivityInDicatorView:NO];//关闭Loading视图
//                self.playerInfoButton.hidden = NO; //显示错误提示按钮,点击后重新加载视频
//                [self.playerInfoButton setTitle:@"资源加载失败,点击继续尝试加载" forState: UIControlStateNormal];
                [[BITNoticeView currentNotice] showErrorNotice:@"资源加载失败,请继续尝试加载"];
                [self hiddenPlayer];
                break;
            }
            case AVPlayerStatusUnknown:{
                NSLog(@"加载遇到未知问题:AVPlayerStatusUnknown");
                [self hiddenPlayer];
                break;
            }
            default:
                break;
        }
    } else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
//        //获取视频缓冲进度数组,这些缓冲的数组可能不是连续的
//        NSArray *loadedTimeRanges = playerItem.loadedTimeRanges;
//        //获取最新的缓冲区间
//        CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];
//        //缓冲区间的开始的时间
//        NSTimeInterval loadStartSeconds = CMTimeGetSeconds(timeRange.start);
//        //缓冲区间的时长
//        NSTimeInterval loadDurationSeconds = CMTimeGetSeconds(timeRange.duration);
//        //当前视频缓冲时间总长度
//        NSTimeInterval currentLoadTotalTime = loadStartSeconds + loadDurationSeconds;
//        //NSLog(@"开始缓冲:%f,缓冲时长:%f,总时间:%f", loadStartSeconds, loadDurationSeconds, currentLoadTotalTime);
//        //更新显示:当前缓冲总时长
//        _currentLoadTimeLabel.text = [self formatTimeWithTimeInterVal:currentLoadTotalTime];
//        //更新显示:视频的总时长
//        _totalNeedLoadTimeLabel.text = [self formatTimeWithTimeInterVal:CMTimeGetSeconds(self.player.currentItem.duration)];
//        //更新显示:缓冲进度条的值
//        _progressView.progress = currentLoadTotalTime/CMTimeGetSeconds(self.player.currentItem.duration);
    }
}

-(void)updatePlayBtn
{
    if([[FFSingleObject sharedInstance] achiveStringWithWeb:self.entity.file])
    {
        self.playButton.hidden = NO;
        self.photoImageView.hidden = YES;
        [self.playButton setImage:[UIImage imageNamed:@"播放"] forState:UIControlStateNormal];
//        [self.photoImageView sd_setImageWithURL:[NSURL URLWithString:self.entity.pic]];
    }
    else
    {
        self.playButton.hidden = YES;
        self.photoImageView.hidden = YES;
    }
}

- (UIImageView *)photoImageView {
    if(!_photoImageView)
    {
        _photoImageView = [self createImageView];
        [_photoImageView.layer setMasksToBounds:YES];
        _photoImageView.contentMode = UIViewContentModeScaleAspectFill;//等比缩放图片把整个ImageView填充满,所以可能会出现图片部分显示不出来
        _photoImageView.hidden = YES;
        _photoImageView.backgroundColor = [UIColor whiteColor];
        _photoImageView.userInteractionEnabled = YES;
    }
    return _photoImageView;
}

- (UIButton *)playButton {
    
    if (!_playButton)
    {
        _playButton = [[UIButton alloc] init];
        [_playButton setTitle:@"" forState:UIControlStateNormal];
        [_playButton setImage:[UIImage imageNamed:@"播放"] forState:UIControlStateNormal];
        _playButton.backgroundColor = [UIColor clearColor];
        _playButton.userInteractionEnabled = YES;
        _playButton.hidden = YES;
        @weakify(self);
        [[_playButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
            @strongify(self);
            if(self.isPlay)
            {
                [self hiddenPlayer];
            }
            else
            {
                [self.playButton setImage:[UIImage imageNamed:@"暂停"] forState:UIControlStateNormal];
                self.isPlay = YES;
                self.photoImageView.hidden = NO;
                self.playButton.hidden = NO;
                if([[FFSingleObject sharedInstance] achiveStringWithWeb:self.entity.pic])
                {
                    [self.photoImageView sd_setImageWithURL:[NSURL URLWithString:self.entity.pic]];
                }
                //网络视频路径
                NSString *webVideoPath = self.entity.file;//@"http://api.junqingguanchashi.net/yunpan/bd/c.php?vid=/junqing/1129.mp4";
                NSURL *webVideoUrl = [NSURL URLWithString:webVideoPath];
                AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:webVideoUrl];
                self.currentPlayerItem = playerItem;
                self.player = [[AVPlayer alloc] initWithPlayerItem:playerItem];
                AVPlayerLayer *avLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
                avLayer.videoGravity = AVLayerVideoGravityResizeAspect;
                avLayer.frame = self.photoImageView.bounds;
                [self.photoImageView.layer addSublayer:avLayer];
                //1.注册观察者,监测播放器属性
                //观察Status属性,可以在加载成功之后得到视频的长度
                [self.player.currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
                //观察loadedTimeRanges,可以获取缓存进度,实现缓冲进度条
                [self.player.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
            }
        }];
    }
    return _playButton;
}

页面离开处理:

-(void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:NO];
    [self.view endEditing:YES];
    [self.collectionView.refreshView endAnimating];
    [self.chooseSongHeadView hiddenPlayer];
}

点击按钮进行播放和暂停,进入后台停止播放:

    @weakify(self);
    self.imagesScrollView.displayBlock = ^(JCTBannerEntity *entity) {
        @strongify(self);
        self.entity = entity;
        if(!self.isPlay)
        {
            [self updatePlayBtn];
        }
    };
    
    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil] subscribeNext:^(id x) {
        @strongify(self);
        [self hiddenPlayer];
    }];
目录
相关文章
|
7月前
|
存储 缓存 Android开发
安卓Jetpack Compose+Kotlin, 使用ExoPlayer播放多个【远程url】音频,搭配Okhttp库进行下载和缓存,播放完随机播放下一首
这是一个Kotlin项目,使用Jetpack Compose和ExoPlayer框架开发Android应用,功能是播放远程URL音频列表。应用会检查本地缓存,如果文件存在且大小与远程文件一致则使用缓存,否则下载文件并播放。播放完成后或遇到异常,会随机播放下一首音频,并在播放前随机设置播放速度(0.9到1.2倍速)。代码包括ViewModel,负责音频管理和播放逻辑,以及UI层,包含播放和停止按钮。
|
2月前
|
缓存 NoSQL 数据库
缓存穿透、缓存击穿和缓存雪崩及其解决方案
在现代应用中,缓存是提升性能的关键技术之一。然而,缓存系统也可能遇到一系列问题,如缓存穿透、缓存击穿和缓存雪崩。这些问题可能导致数据库压力过大,甚至系统崩溃。本文将探讨这些问题及其解决方案。
|
2月前
|
缓存 NoSQL PHP
Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出
本文深入探讨了Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出。文章还介绍了Redis在页面缓存、数据缓存和会话缓存等应用场景中的使用,并强调了缓存数据一致性、过期时间设置、容量控制和安全问题的重要性。
46 5
|
7月前
|
缓存 NoSQL Java
避免缓存失效的三大杀手:缓存击穿、穿透与雪崩的解决方案
避免缓存失效的三大杀手:缓存击穿、穿透与雪崩的解决方案
143 0
|
3月前
|
缓存 NoSQL 关系型数据库
缓存穿透以及解决方案
缓存穿透以及解决方案
44 0
|
6月前
|
缓存 NoSQL Redis
使用Redis实现缓存穿透的解决方案
使用Redis实现缓存穿透的解决方案
|
7月前
|
缓存 Java 微服务
Springboot微服务整合缓存的时候报循环依赖的错误 两种解决方案
Springboot微服务整合缓存的时候报循环依赖的错误 两种解决方案
92 1
|
7月前
|
存储 缓存 NoSQL
Redis是一种高性能的内存数据库,常用于高并发环境下的缓存解决方案
【6月更文挑战第18天】**Redis摘要:** 高性能内存数据库,擅长高并发缓存。数据存内存,访问迅速;支持字符串、列表等多元数据类型;具备持久化防止数据丢失;丰富命令集便于操作;通过节点集群实现数据分片与负载均衡,增强可用性和扩展性。理想的缓存解决方案。
93 1
|
6月前
|
缓存 NoSQL Redis
使用Redis实现缓存穿透的解决方案
使用Redis实现缓存穿透的解决方案
|
8月前
|
缓存 监控 数据库
分布式系统中缓存穿透问题与解决方案
在分布式系统中,缓存技术被广泛应用以提高系统性能和响应速度。然而,缓存穿透是一个常见而严重的问题,特别是在面对大规模请求时。本文将深入探讨缓存穿透的原因、影响以及一些有效的解决方案,以确保系统在面对这一问题时能够保持稳定和高效。
115 13