我正在创建一个应用程序,该应用程序包含多个类别的小音频片段。当用户点击一个类别时,它会加载一个音频文件列表。当用户点击音频文件时,它会播放音频。
我有几个人在iOS上测试我的应用程序。对我来说,它不会崩溃,但其他人报告说,在浏览了几个音频文件后,它崩溃了。它并不是崩溃的特定音频文件,而且看起来相当断断续续。我正在使用willBlurSubscription
来释放内存。
以下是我的音频列表代码的简化版本:
import React, { Component } from 'react';
var Sound = require('react-native-sound');
Sound.setCategory("Playback"); //Needed for audio to play on IOS devices
import {
Image,
ScrollView,
View,
Text,
TouchableOpacity
} from 'react-native';
import files from '../assets/json/files';
export default class AudioList extends Component {
constructor(props) {
super(props)
}
playAudio = (file) => {
console.log(file)
if (this.sound) {
console.log("SOUND")
try {
this.sound.release()
} catch(error){
console.log("A sound release error has occured 111")
}
finally {
this.sound = null
}
}
this.sound = new Sound('audio/' + file, Sound.MAIN_BUNDLE, (error) => {
if (error) {
console.log('error', error);
this.sound = null;
} else {
this.sound.play(()=> {
try {
if (this.sound){
this.sound.release()
}
} catch(error) {
console.log("A sound release error has occured 222")
}
finally {
this.sound = null
}
})
}
})
this.willBlurSubscription = this.props.navigation.addListener(
'blur',
() => {
try {
if (this.sound){
this.sound.release()
}
} catch(error) {
console.log("A sound release error has occured 333")
}
finally {
this.sound = null
}
}
)
}
componentWillUnmount() {
try {
this.willBlurSubscription &&
this.willBlurSubscription.remove &&
this.willBlurSubscription.remove()
} catch(error) {}
finally {
this.willBlurSubscription = null
}
}
render() {
let list = files[this.props.route.params['category_id']]
let audio_list = list.data.map((item, index) => {
return <View key={index}>
{!!item.audio &&
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
{item.audio ?
<TouchableOpacity onPress={()=>this.playAudio(item.audio)}>
<Image source={require('../assets/images/play_button.png')} />
</TouchableOpacity>
:
<View></View>
}
<Text>{item.text}</Text>
</View>
{!!item.audio2 &&
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
{item.audio2 ?
<TouchableOpacity onPress={()=>this.playAudio(item.audio2)}>
<Image source={require('../assets/images/play_button.png')} />
</TouchableOpacity>
:
<View></View>
}
<Text>{item.text2}</Text>
</View>
}
</View>
})
return (
<ScrollView>
<View>
{audio_list}
</View>
</ScrollView>
)
}
}
哨兵报告:
我现在已经实现了哨兵,在崩溃时,我在哨兵中得到了以下信息:
RCTFatalException: Unhandled JS Exception: TypeError: null is not an object (evaluating 'a.sound.play')
请记住,这是一个间歇性问题。声音文件确实存在,因此不应为null。其他时候我点击它,它确实会播放文件。
我想知道清除以前的音频文件以加载新的音频文件是否导致了这个问题。在那短暂的时间里,它可能是空的。
清除以前的音频文件的原因是为了消除创建这么多音频对象时的内存泄漏。
我在这里做错了什么?
之所以会发生这种情况,是因为您使用的是willBlurSubscription
方法,当您转到另一个屏幕并返回屏幕时,有时会出现这种故障
简单的解决方案是通过在播放前检查声音实例来播放声音安全,就像这个
this.sound && this.sound.play(()=> {
我认为,您应该使用navigation.addListener('focus'
来重新初始化声音对象,以防止此崩溃。