4
votes

I'm building an app that has a timer to request geolocation while the timer is active. For a timer I'm using react-native-background-timer. Which is kind of working, but not exactly as I want.

With this piece of code:

BackgroundTimer.runBackgroundTimer(() => { 
    console.log('tic');
},  
1000);

the timer is stopping when the app is in the background. While with this piece of code:

const intervalId = BackgroundTimer.setInterval(() => {
    console.log('tic');
}, 1000);

it runs constantly even in the background, but I'm not able to stop it. When I run BackgroundTimer.clearInterval(intervalId);, the timer still runs. Even when I leave the screen and go back to my Home screen, the timer still ticks and never stops. This is not ideal, because I need timer to run for a few minutes and then stop.

I set the timer to 1 second to update time left on the screen. I was thinking about setting a timer once for 6 minutes, but then how do I update the state every second? Making 2 timers for this feels like a bad practise, even though it would work.

So to make it more clear, the user suppose to engage in certain activity like walking for a few minutes. So I can't let the timer to stop when user is answering a call or opened a music app to switch music or something else. Timer still needs to run and I need to measure the number of steps and distance with geolocation. It need to work flawlessly even if user opened another app, forgot about my app, and it would still run for the remaining time, then made a record to the database and stopped.

2

2 Answers

15
votes

Try the following code snippet, works both on android and ios

import { DeviceEventEmitter, NativeAppEventEmitter, Platform } from 'react-native';
import _BackgroundTimer from 'react-native-background-timer';

const EventEmitter = Platform.select({
    ios: () => NativeAppEventEmitter,
    android: () => DeviceEventEmitter,
})();

class BackgroundTimer {
    static setInterval(callback, delay) {
        _BackgroundTimer.start();
        this.backgroundListener = EventEmitter.addListener("backgroundTimer", () => {
            this.backgroundTimer = _BackgroundTimer.setInterval(callback, delay);
        });
        return this.backgroundListener;
    }

    static clearInterval(timer) {
        if (timer) timer.remove();
        if (this.backgroundTimer)
            _BackgroundTimer.clearInterval(this.backgroundTimer);
        _BackgroundTimer.stop();
    }
}

export default BackgroundTimer;

Usage

const timer = BackgroundTimer.setInterval(callback, 1000);
BackgroundTimer.clearInterval(timer)
0
votes

For some reason I got the following error when using @Aravind Vemula's answer. When calling BackgroundTimer.clearInterval(timer); the following error appears:

timer.remove is not a function

That's why I modified the code slightly.

// parameter removed
static clearInterval() {
    // ADD this if statement 
    if (this.backgroundListener){ 
        this.backgroundListener.remove();
    }
    if (this.backgroundTimer)
        _BackgroundTimer.clearInterval(this.backgroundTimer);
    _BackgroundTimer.stop();
}

The above code checks if a backgroundlistener is registered. If yes it removes all listeners and especially our backgroundTimer.

Usage:

BackgroundTimer.clearInterval(); // removed parameter

After my change, everything is working fine on iOS 14.3.