react-native-geolocation
react-native-geolocation copied to clipboard
fix: added pending callbacks mechanism to solve npe crash
Overview
Solves this issue:
- https://github.com/michalchudziak/react-native-geolocation/issues/241
Crash Log
Fatal Exception: java.lang.NullPointerException: Listener must not be null
at com.google.android.gms.common.internal.Preconditions.checkNotNull(com.google.android.gms:play-services-basement@@18.1.0:2)
at com.google.android.gms.common.api.internal.ListenerHolders.createListenerKey(com.google.android.gms:play-services-base@@18.0.1:1)
at com.google.android.gms.location.FusedLocationProviderClient.removeLocationUpdates(com.google.android.gms:play-services-location@@20.0.0:6)
at com.reactnativecommunity.geolocation.PlayServicesLocationManager$1.onLocationResult(PlayServicesLocationManager.java:74)
at com.google.android.gms.internal.location.zzaw.notifyListener(com.google.android.gms:play-services-location@@20.0.0:2)
at com.google.android.gms.common.api.internal.ListenerHolder.zaa(com.google.android.gms:play-services-base@@18.0.1:2)
at com.google.android.gms.common.api.internal.zacb.run(:4)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:236)
at android.app.ActivityThread.main(ActivityThread.java:8057)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)
It is easily reproducible with example app in react-native-geolcation repo. Reproducer App: https://github.com/michalchudziak/react-native-geolocation/tree/master/example
Steps to repro:
- Clone the example app.
- Make Two Calls to getCurrentPosition
Geolocation.getCurrentPosition(
(info) => {
console.log('GetCurrentPosition Success', JSON.stringify(info));
},
(error) => {
console.log('GetCurrentPosition Error', JSON.stringify(error));
},
{
enableHighAccuracy: true,
maximumAge: 20 * 1000,
timeout: 10 * 1000,
}
);
Geolocation.getCurrentPosition(
(info) => {
console.log('GetCurrentPosition Success', JSON.stringify(info));
},
(error) => {
console.log('GetCurrentPosition Error', JSON.stringify(error));
},
{
enableHighAccuracy: true,
maximumAge: 20 * 1000,
timeout: 10 * 1000,
}
);
- Run the Example App:
- Select the playServices option.
- Click the getCurrentPosition button.
- The app crashes with the stack trace provided above.
Issue Summary
The mSingleLocationCallback gets overwritten when multiple calls to getCurrentPosition() are made before the previous call finishes. This leads to a situation where null is passed to mFusedLocationClient.removeLocationUpdates(), causing the Listener must not be null exception.
Changes Made:
- Introduced a List<LocationCallback> (mPendingLocationCallbacks) to keep track of pending location callbacks. This ensures that callbacks are properly managed and removed, preventing the crash.
- Updated
getCurrentLocationData
,startObserving
, andstopObserving
methods to handle the addition and removal of callbacks more safely and consistently.
Test Plan
Tested getCurrentPosition
and watchPosition
functionality.