I have a React Native Android TV app that I use to display digital signage content on a TV. I have received a couple of outOfMemory exceptions after the app has been running for about an hour. My app initially renders a Player
component that uses a setTimeout
to run every 1 second. Each second, the component iterates through a JSON array that has information about different images or videos. Depending on a few conditions, the Player
component will update a state value currentAsset
and re-render an Asset
component displaying either a video or an image for a specified number of seconds. To reproduce the outOfMemory exception, I have made the value of currentAsset
toggle back and forth from an auto playing video to an image every 1 second so it literally displays an image on the screen for a second and then a video and repeats this infinitely. Although this isn't typical usage it is the fastest way I have been able to recreate the memory exception.
Here is my skeleton code:
class Player extends Component {
constructor(props) {
super(props)
this.currentAsset = null
this.state = { currentAsset: null }
}
componentDidMount(){
//create cache directory initializes file caching for the player
createCacheDirectory().then(() => {
this.play()
})
}
poll = () => {
//conditional here to either poll an API for updates and call play or just call play
if(canCallAPI){
//this condition happens every 30 seconds
//might call setState in a promise which also saves files locally to the device.
callAPI().then(() => {
//some other setup stuff here
play();
})
}
play()
}
play = () => {
//there is more logic here but the idea is that I get a new object containing a file/video path which I pass to the `Asset` Component
this.currentAsset = this.getCurrentAssetFromJSONArray();
this.setState({ currentAsset: this.currentAsset });
this.timeout = setTimeout(this.poll, 1000);
}
render() {
return (<Asset asset={this.state.currentAsset} />);
}
end
The Asset
component is pretty simple and just checks the value of this.state.currentAsset.file_type
and renders an <Image />
or <Video />
depending on the current file type.
There's a memory leak due to every time the component re-render it create a new timer instance without clearing previous instances.
We need to clear out the timer when component unmount.
class Player extends Component {
constructor(props) {
super(props);
this.currentAsset = null;
this.state = { currentAsset: null };
this.timeout = null;
}
componentDidMount() {
//create cache directory initializes file caching for the player
createCacheDirectory().then(() => {
this.play();
});
}
poll = () => {
//conditional here to either poll an API for updates and call play or just call play
if (canCallAPI) {
//this condition happens every 30 seconds
//might call setState in a promise which also saves files locally to the device.
callAPI().then(() => {
//some other setup stuff here
play();
});
}
play();
};
play = () => {
//there is more logic here but the idea is that I get a new object containing a file/video path which I pass to the `Asset` Component
this.currentAsset = this.getCurrentAssetFromJSONArray();
this.setState({ currentAsset: this.currentAsset });
this.timeout = setTimeout(this.poll, 1000);
};
componentWillUnmount() {
// Clear current timeout when component unmount
if (this.timeout) {
clearTimeout(this.timer);
}
}
render() {
return <Asset asset={this.state.currentAsset} />;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.