user465001
user465001

Reputation: 846

Not able to turn off location tracking when a React Native Maps component has been backgrounded

The map component of my app does not need to constantly track the user's location. Adding

navigator.geolocation.clearWatch(this.watchId);

and

navigator.geolocation.stopObserving(); 

to componentWillUnmount and to an AppState listener does not shut off the GPS when it's not needed. How can I make this work? Thanks.

A little more info: I can tell the GPS location service is still running (in the android version of this app) because the location icon remains in the statusbar after the app has been backgrounded.

export class MapOfHalifax extends React.Component {

constructor(args) {
    super(args);
    this.state = {
        markers: this.props.markers,
        latitude: null,
        longitude: null,
        error: null,
    }
}

componentDidMount() {

    this.watchId = navigator.geolocation.watchPosition(
        (position) => {
            this.setState({
                latitude: position.coords.latitude,
                longitude: position.coords.longitude,
                error: null,
            });
            this.checkDistanceFromSignificantLocation(position)

        },
        (error) => this.setState({ error: error.message }),
        { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000, distanceFilter: 10 },
    );


    AppState.addEventListener('change', (state) => {
        if (state === 'active') {
         console.log('state active');
        }
       if(state === 'background'){
        navigator.geolocation.clearWatch(this.watchId);
        navigator.geolocation.stopObserving();
        console.log('background');
       }
    });


}

componentWillUnmount() {
    navigator.geolocation.clearWatch(this.watchId);
    navigator.geolocation.stopObserving();
}
toggleSelect(id) {
    // this.state.selected.indexOf(id) > -1
    //   ? this.setState({ selected: this.state.selected.filter(x => x !== id) })
    //   : this.setState({ selected: this.state.selected.concat(id) }),
    this.props.toggleMarkerState(id)
}

checkDistanceFromSignificantLocation(currentPosition) {
    this.state.markers.map((marker, index) => {
        const START = {
            latitude: currentPosition.coords.latitude,
            longitude: currentPosition.coords.longitude
        }
        const END = {
            latitude: marker.latitude,
            longitude: marker.longitude
        }
        if (haversine(START, END, { threshold: MAX_DISTANCE_FROM_LOCATION, unit: PREFERED_DISTANCE_UNIT })
            && (!this.props.markers[index].locationPassedBy)){
            this.props.updatePassedByTime(index, moment.utc())
            NotificationsAndroid.localNotification({
                title: "Approaching:",
                body: marker.name + "!"
            });

        } else if (haversine(START, END, { threshold: MAX_DISTANCE_FROM_LOCATION, unit: PREFERED_DISTANCE_UNIT })
        && (moment().diff(this.props.markers[index].locationPassedBy,'minutes') > 60)){
            NotificationsAndroid.localNotification({
                title: "Approaching:",
                body: marker.name + "!"
            });
        }
    });


}

render() {
    return (
        <View style={styles.container}>
            <MapView
                ref={ref => { this.map = ref; }}
                showsUserLocation={true}
                showsMyLocationButton={true}
                style={styles.map}
                initialRegion={{
                    latitude: LATITUDE,
                    longitude: LONGITUDE,
                    latitudeDelta: LATITUDE_DELTA,
                    longitudeDelta: LONGITUDE_DELTA,
                }}>
                {this.state.markers.map((marker, index) => {
                    return (<MapView.Marker
                        coordinate={{
                            latitude: parseFloat(marker.latitude),
                            longitude: parseFloat(marker.longitude)
                        }}
                        title={marker.name}
                        key={marker.id}
                        onPress={() => {
                            const marker = this.state.markers[index]
                            marker.mapMarkerIsSelected = !marker.mapMarkerIsSelected
                            this.setState({
                                markers: [
                                    ...this.state.markers.slice(0, index),
                                    marker,
                                    ...this.state.markers.slice(index + 1)
                                ]
                            })
                            this.props.toggleMarkerState(marker.id)
                        }}
                        pinColor={
                            marker.mapMarkerIsSelected ? '#3590ea' : '#f06f77'
                        }>
                    </MapView.Marker>)
                })}
            </MapView>
        </View>
    );
}
}

const styles = StyleSheet.create({
container: {
    ...StyleSheet.absoluteFillObject,
    justifyContent: 'flex-end',
    alignItems: 'center',
},
map: {
    ...StyleSheet.absoluteFillObject,
},
bubble: {
    backgroundColor: 'rgba(255,255,255,0.7)',
    paddingHorizontal: 18,
    paddingVertical: 12,
    borderRadius: 20,
},
button: {
    marginTop: 12,
    paddingHorizontal: 12,
    alignItems: 'center',
    marginHorizontal: 10,
},
buttonContainer: {
    flexDirection: 'column',
    marginVertical: 20,
    backgroundColor: 'transparent',
},
customCallout: {
    backgroundColor: 'white',
    padding: 5
},
callout: {
    width: 140,
},
});

const mapStateToProps = state => {
return {
    markers: state.PeopleReducer
};
}

const actions = { updatePassedByTime, toggleMarkerState };

export default connect(mapStateToProps, actions)(MapOfHalifax);

Upvotes: 3

Views: 1684

Answers (1)

user465001
user465001

Reputation: 846

When I made this post, I was running the above code on google's android emulator. After posting, it became apparent that my code was working like it should on the emulator but, with a delay. So, I ran the code on a physical device and found that the geolocation icon disappeared instantaneously. It was sufficient to leave the clearWatch() and possibly the stopObserving() functions in componentWillUnmount(). The AppState listener was not needed.

Upvotes: 2

Related Questions