Статус AVPlayer обновляется, когда приложение выходит на передний план

Я создаю музыкальный проигрыватель в своем приложении для iOS, используя AVPlayer. Я прослушиваю изменения для свойства AVPlayer.status следующим образом, чтобы узнать, когда звук будет готов к воспроизведению:

player.currentItem!.addObserver(self, forKeyPath: "status", options: .New, context: nil)

И когда статус .ReadyToPlay я автоматически запускаю воспроизведение:

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        if (keyPath == "status") {
            if let currentItem = self.player?.currentItem {
                let status = currentItem.status
                if (status == .ReadyToPlay) {                    
                    self.play()
                }
            }
        }        
    }
}

Работает отлично. Проблема, однако, заключается в том, что если я начну воспроизводить музыку в своем приложении, приостановлю музыку, а затем выйду из приложения и начну воспроизводить музыку, например, в Spotify, свойство состояния AVPlayer, похоже, снова изменится на .ReadyToPlay в следующий раз, когда мой app выходит на передний план, что приводит к срабатыванию наблюдателя, что, в свою очередь, заставляет снова воспроизводить музыку.

Я предполагаю, что что-то происходит с экземпляром AVPlayer, когда приложение снова получает фокус, что приводит к изменению/обновлению свойства состояния.

Как предотвратить такое поведение?


person rodskagg    schedule 27.11.2015    source источник


Ответы (1)


Это похоже на ожидаемое поведение. Если вы хотите убедиться, что вы начинаете воспроизведение только при первом изменении состояния AVPlayerItem, удалите наблюдателя после вызова play().

Одно предостережение здесь заключается в том, что вы уже должны удалять наблюдателя при изменении currentItem на игроке, поэтому вам нужно будет использовать дополнительный флаг, чтобы отслеживать, наблюдаете ли вы за существующим currentItem.

Владелец игрока будет отслеживать состояние

var isObservingCurrentItem = false

И обновите/проверьте это состояние при добавлении наблюдателя

if currentItem = player.currentItem where isObservingCurrentItem {
    currentItem.removeObserver(self, forKeyPath:"status")
}

player.currentItem!.addObserver(self, forKeyPath: "status", options: .New, context: nil)
isObservingCurrentItem = true

Затем вы можете безопасно удалить наблюдателя, как только игрок будет готов к игре.

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {

    if let object = object,
        keyPath = keyPath,
        currentItem = self.player?.currentItem,
        status = currentItem.status
        where status == .ReadyToPlay {
            self.play()
            object.removeObserver(self, forKeyPath:keyPath)
            isObservingCurrentItem = false
    }
}
person ChrisH    schedule 27.11.2015
comment
Спасибо за идею. В итоге я проверил вObservValueForKeyPath, чтобы увидеть, совпадают ли старое и новое значение (т. е. ReadyToPlay), и если да, то ничего не сделал. Но ваше решение, вероятно, лучше :) - person rodskagg; 06.12.2015
comment
@chrisH большое спасибо, это помогло решить странные проблемы с пользовательским интерфейсом в последовательности фона/переднего плана приложения. Я пропустил удаление наблюдателя, как только игрок будет готов играть роль - вы спасли мой день - person srvy; 14.02.2021