简体   繁体   中英

Memory Leak in React Native Android App using setTimeout

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM