0

Using React Native and @mauron85/react-native-background-geolocation, I'm trying to create a function to return true/false depending on whether background geolocation is active or not.

In the documentation, we see an example:

    BackgroundGeolocation.checkStatus(status => {
      console.log('[INFO] BackgroundGeolocation service is running', status.isRunning);
      console.log('[INFO] BackgroundGeolocation services enabled', status.locationServicesEnabled);
      console.log('[INFO] BackgroundGeolocation auth status: ' + status.authorization);

      // you don't need to check status before start (this is just the example)
      if (!status.isRunning) {
        BackgroundGeolocation.start(); //triggers start on start event
      }
    });

Now, I really don't understand why there's no function to just return the status, but at any rate, I need such a function, the attempt at which is the following.

export function isBackgroundTracking() {

  // Null means undetermined, but should never be returned that way.
  var result = null;

  // This is accurately logged first.
  console.log('One');

  // This should finish before moving on.
  BackgroundGeolocation.checkStatus(status => {
    result = status.isRunning;
    // This is inaccurately logged third.
    console.log('Two:', result);
  });

  // This is inaccurately logged second.
  console.log('Three:', result);

  // This is inaccurately returned as null, because `checkStatus` is apparently asynced.
  return result;

}

In the interface code, the button calls the function in this way:

<CtaButton
  bgColor={Colors.backgroundAlt}
  onPress={() => {
    stopBackgroundTracking();
    let result = isBackgroundTracking();
    console.log('Result:', result);
  }}
>

Running this code, the output is this:

 LOG  One
 LOG  Three: null
 LOG  Result: null
 LOG  Two: false

I have also tried playing around with async/await, like so:

export async function isBackgroundTracking() {

  // Null means undetermined, but should never be returned that way.
  var result = null;

  // This is accurately logged first.
  console.log('One');

  // This should finish before moving on.
  await BackgroundGeolocation.checkStatus(status => {
    result = status.isRunning;
    // This is inaccurately logged third.
    console.log('Two:', result);
  });

  // This is inaccurately logged second.
  console.log('Three:', result);

  // This is inaccurately returned as null, because `checkStatus` is apparently asynced.
  return result;

}

...and...

<CtaButton
  bgColor={Colors.backgroundAlt}
  onPress={async () => {
    stopBackgroundTracking();
    let result = await isBackgroundTracking();
    console.log('Result:', result);
  }}
>

But the result is exactly the same.

Going by the console.log lines above, how can I get this to run in the proper order? This doesn't have to be asynchronous, in fact I'd prefer it not to be, but I can live with it being asynchronous as long as I get a function that returns the value that I need.

Teekin
  • 11,048
  • 11
  • 48
  • 63
  • The reason it can't just return the status synchronously is because it's asynchronous on the system level. The system might prompt the user to allow or disallow the usage of geolocation data. For that to be returned synchronously it would have to freeze the thread while waiting for the response, which would simply be bad design. Especially in Javascript land since JS is single-threaded. – Lennholm Apr 10 '20 at 19:40

1 Answers1

1
export async function isBackgroundTracking() {

  // Null means undetermined, but should never be returned that way.
  var result = null;

  // This is accurately logged first.
  console.log('One');

  // This should finish before moving on.
  await new Promise(res => {
    BackgroundGeolocation.checkStatus(status => {
      result = status.isRunning;
      // This is inaccurately logged third.
      console.log('Two:', result);

      // resolve the promise
      res();
    });
  });

  // This is inaccurately logged second.
  console.log('Three:', result);

  // This is inaccurately returned as null, because `checkStatus` is apparently asynced.
  return result;

}

You could also extract it to a function to make it simple

const checkStatus = () => new Promise((res,rej) => BackgroundGeolocation.checkStatus(res,rej));

export async function isBackgroundTracking() {

 ...

 result = (await checkStatus()).isRunning;

 ...

}

Turning callbacks into promises

Adam
  • 41,349
  • 10
  • 58
  • 78
  • Wonderful, thank you so much! This explains quite a bit, actually. I took the former suggestion because it seems tidier, but it also just worked straight out of the box. Thank you again for the quick response! – Teekin Apr 10 '20 at 19:32