react-native-background-geolocation
react-native-background-geolocation copied to clipboard
ConcurrentModificationException java.util.ArrayList$Itr in next
Your Environment
- Plugin version: 4.10.0
- Platform: Android
- OS version: macOS 13.2.1
- Device manufacturer / model: Mac mini (Chip Apple M1)
- React Native version (
react-native -v): 0.71.2 - Plugin config
const config = {
notification: {
title: 'Company',
text: 'Executando',
},
disableMotionActivityUpdates: true,
desiredAccuracy: Platform.select({
ios: BackgroundGeolocation.DESIRED_ACCURACY_NAVIGATION,
android: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
}),
debug: __DEV__ ? true : false,
logLevel: __DEV__
? BackgroundGeolocation.LOG_LEVEL_VERBOSE
: BackgroundGeolocation.LOG_LEVEL_OFF,
stopOnTerminate: false,
startOnBoot: false,
url,
batchSync: true,
autoSync: true,
autoSyncThreshold: 5,
maxBatchSize: 100,
distanceFilter: Platform.select({ios: 10, android: 20}),
stopTimeout: 5,
locationTemplate:
'{"latitude":<%= latitude %>,"longitude":<%= longitude %>,"velocidade":<%= speed %>,"time":"<%= timestamp %>","id":"<%= uuid %>","nivel_bateria": <%= battery.level %>}',
headers: {
accept: 'application/json',
'content-type': 'application/json',
authorization: httpClient.defaults.headers.common.Authorization,
},
params: {
timezone: 'America/Recife',
},
extras: {
modelo_dispositivo,
fabricante,
},
//iOS Options
showsBackgroundLocationIndicator: true,
stationaryRadius: 10,
heartbeatInterval: Platform.select({ios: 10, android: 60}),
preventSuspend: Platform.select({ios: true, android: false}),
activityType:
BackgroundGeolocation.ACTIVITY_TYPE_AUTOMOTIVE_NAVIGATION,
};
Expected Behavior
None bug reported on Sentry
Actual Behavior
Native Exception (Android): ConcurrentModificationException java.util.ArrayList$Itr in next
Stack Trace: java.util.ConcurrentModificationException: null at java.util.ArrayList$Itr.next(ArrayList.java:860) at com.transistorsoft.locationmanager.util.c$j.onPermissionGranted at com.intentfilter.androidpermissions.PermissionHandler.checkPermissions(PermissionHandler.java:44) at com.intentfilter.androidpermissions.PermissionManager.checkPermissions(PermissionManager.java:55) at com.transistorsoft.locationmanager.util.c$j.run 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:7912) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:620) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1011)
Context
Apparently the crash happens after our users have accepted background geolocation permissions. On Sentry, the most reports are from Android 10 and 11 in Xiaomi devices mainly (Redmi Note 8, Redmi Note 9, Redmi Prime 9S, Redmi Note 9S, Redmi Note 11, etc)
Complete Issue link: https://hubsoftbrasil.sentry.io/share/issue/ae5d1d147c7241eea763fd7b9643fa0a/
@christocracy I would like your help with it. Do you need any other info ?
I do not have any explanation for this error. The plugin code is properly interacting with a static List within synchronized blocks.
Show me your code.
Below, it's my component where I control the "start/stop" of your service:
import React, {useCallback, Fragment, useEffect, useState} from 'react';
import DeviceInfo from 'react-native-device-info';
import NetInfo from '@react-native-community/netinfo';
import {connect} from 'react-redux';
import BackgroundGeolocation from 'react-native-background-geolocation';
import moment from 'moment';
import {useDispatch} from 'react-redux';
import {AppState, Platform} from 'react-native';
import showToast from '~/services/Toast';
import Unauthorized from '~/services/Unauthorized';
import httpClient from '~/HttpClient';
import * as types from '~/constants/ActionTypes';
import {
modificaNivelBateria,
modificaDispositivoInfo,
modificaStatusConexao,
} from '~/actions/DeviceInfoActions';
import useSyncGeolocation from '~/hooks/sync_geolocation';
import {checkRequest} from '~/hooks/sync_geolocation/Useful';
const HubsoftBackgroundGeolocation = ({
navigation,
nivel_bateria,
modelo_dispositivo,
fabricante,
modificaNivelBateria,
modificaDispositivoInfo,
}) => {
const dispatch = useDispatch();
const handleSync = useSyncGeolocation();
const [enabled, setEnabled] = useState(false);
useEffect(() => {
// Força a captura de localizações
if ((__DEV__ && enabled) || (enabled && Platform.OS === 'ios')) {
BackgroundGeolocation.changePace(true)
.then(success => console.log('changePace(true):', success))
.catch(err => console.error('changePace(false):', err));
}
}, [enabled]);
useEffect(() => {
/// 1. Subscribe to events.
const onLocation = BackgroundGeolocation.onLocation(location => {
console.log('[onLocation]');
_modificaDeviceInfo();
});
const config = {
notification: {
title: 'Hubsoft',
text: 'Executando',
},
disableMotionActivityUpdates: true,
desiredAccuracy: Platform.select({
ios: BackgroundGeolocation.DESIRED_ACCURACY_NAVIGATION,
android: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
}),
debug: __DEV__ ? true : false,
logLevel: __DEV__
? BackgroundGeolocation.LOG_LEVEL_VERBOSE
: BackgroundGeolocation.LOG_LEVEL_OFF,
stopOnTerminate: false,
startOnBoot: false,
url: ${httpClient.defaults.baseURL}api/v1/app/geolocalizacao/usuario,
batchSync: true,
autoSync: true,
autoSyncThreshold: 5,
maxBatchSize: 100,
distanceFilter: Platform.select({ios: 10, android: 20}),
stopTimeout: 5,
locationTemplate:
'{"latitude":<%= latitude %>,"longitude":<%= longitude %>,"velocidade":<%= speed %>,"time":"<%= timestamp %>","id":"<%= uuid %>","nivel_bateria": <%= battery.level %>}',
headers: {
accept: 'application/json',
'content-type': 'application/json',
authorization: httpClient.defaults.headers.common.Authorization,
},
params: {
timezone: 'America/Recife',
},
extras: {
modelo_dispositivo,
fabricante,
},
//iOS Options
showsBackgroundLocationIndicator: true,
stationaryRadius: 10,
heartbeatInterval: Platform.select({ios: 10, android: 60}),
preventSuspend: Platform.select({ios: true, android: false}),
activityType:
BackgroundGeolocation.ACTIVITY_TYPE_AUTOMOTIVE_NAVIGATION,
};
/// 2. ready the plugin.
BackgroundGeolocation.ready(config)
.then(state => {
const handler = () => {
setEnabled(state.enabled);
console.log(
'- BackgroundGeolocation is configured and ready: ',
state.enabled,
);
// Sincroniza geolocalizações
// ao iniciar APP
if (state.enabled) {
_handleSync();
}
};
handler();
})
.catch(err => {
console.error(err);
});
return () => {
// Remove BackgroundGeolocation event-subscribers when the View is removed or refreshed
// during development live-reload. Without this, event-listeners will accumulate with
// each refresh during live-reload.
onLocation.remove();
};
}, [
fabricante,
_handleSync,
modelo_dispositivo,
_modificaDeviceInfo,
_verificaStatusGeolocalizacao,
]);
/// 3. start / stop BackgroundGeolocation
React.useEffect(() => {
_verificaStatusGeolocalizacao();
}, [_verificaStatusGeolocalizacao]);
const _getCurrentPosition = useCallback(() => {
BackgroundGeolocation.getCurrentPosition({
timeout: 30, // 30 second timeout to fetch location
maximumAge: 5000, // Accept the last-known-location if not older than 5000 ms.
desiredAccuracy: 10, // Try to fetch a location with an accuracy of 10 meters.
samples: 3, // How many location samples to attempt.
extras: {
// Custom meta-data.
fabricante,
modelo_dispositivo,
},
})
.then(location => {
console.log('[_getCurrentPosition]: ', location);
handleSync();
})
.catch(e => {
console.error(
'[_getCurrentPosition]: Falha ao consultar localização atual',
);
console.error(e);
});
}, [fabricante, modelo_dispositivo, handleSync]);
const _handleSync = useCallback(() => {
try {
_getCurrentPosition();
} catch (e) {
console.error('[_handleSync]: Falhou');
console.error(e);
}
}, [_getCurrentPosition]);
const _verificaStatusGeolocalizacao = useCallback(async () => {
try {
/*
* Verifica se já excedeu o intervalo
* de 2 minutos desde a última verificação do
* status de geolocalização
*/
const allowReq = await checkRequest('ultima_verificacao', 2);
if (!allowReq) {
return;
}
const state = await NetInfo.fetch();
if (state.isConnected) {
httpClient
.get(
'api/v1/app/geolocalizacao/usuario/rastreamento/status',
)
.then(response => {
dispatch({
type: types.MODIFICA_ULTIMA_VERIFICACAO_GEOLOCALIZACAO,
payload: {ultima_verificacao: moment()},
});
if (response.data.status === 'success') {
_handleBgGeolocation(response.data.iniciar);
} else {
_handleBgGeolocation(true);
}
})
.catch(err => {
Unauthorized(dispatch, err);
});
} else {
_handleBgGeolocation(true);
}
} catch (e) {
console.error(e);
showToast(
'error',
'Problema',
'Falha ao tentar verificar status do rastreamento',
);
}
}, [dispatch, _handleBgGeolocation]);
const _handleBgGeolocation = useCallback(
iniciar => {
const _dispatch = () => {
dispatch({
type: types.MODIFICA_RASTREAMENTO_USUARIO,
payload: {
rastreamento_usuario: iniciar,
},
});
};
if (!enabled && iniciar) {
BackgroundGeolocation.start()
.then(state => console.log('[start] success - ', state))
.catch(e => console.error(e))
.finally(() => _dispatch());
} else if (!iniciar && AppState.currentState === 'active') {
BackgroundGeolocation.stop()
.then(() => _dispatch())
.catch(() => _dispatch());
}
},
[dispatch, enabled],
);
const _modificaDeviceInfo = useCallback(() => {
try {
DeviceInfo.getBatteryLevel().then(batteryLevel => {
let value = Math.round(batteryLevel.toFixed(2) * 100);
modificaNivelBateria(value);
});
modificaDispositivoInfo({
modelo_dispositivo: DeviceInfo.getModel(),
fabricante: DeviceInfo.getBrand(),
});
} catch (e) {
console.error(e);
}
}, [modificaDispositivoInfo, modificaNivelBateria]);
return <Fragment />;
};
const mapStateToProps = state => ({
nivel_bateria: state.DeviceInfoReducer.nivel_bateria,
modelo_dispositivo: state.DeviceInfoReducer.modelo_dispositivo,
fabricante: state.DeviceInfoReducer.fabricante,
});
const actions = {
modificaNivelBateria,
modificaDispositivoInfo,
modificaStatusConexao,
};
export default connect(mapStateToProps, actions)(HubsoftBackgroundGeolocation);
Ignore last message. Wrong issue.
@christocracy good morning! Is there something I could be doing wrong? According to the stack trace, it could be something to do with the permission granted.
Show me $ adb logcat *:S TSLocationManager:V of your app launching from a fresh install
Please don't post screenshots of logs.
In terminal window, execute the following.
$ adb logcat *:S TSLocationManager:V
Show me
$ adb logcat *:S TSLocationManager:Vof your app launching from a fresh install
Show me
$ adb logcat *:S TSLocationManager:Vof your app launching from a fresh install
I exported the logs from Flipper in JSON format for easy viewing. Would it be this ?
See wiki “Debugging” and learn to use the method .emailLog
Hi @christocracy,
To use .emailLog, do I need to set debug as "true" on production ? For this bug, logLevel as "LOG_LEVEL_ERROR", will it be enough ?
Will sounds and notifications be trigged on production ? I wouldn't like it.
emailLog has nothing to do with debug: true.
Use LOG_LEVEL_VERBOSE
Are there any workaround that I can use it ? Like a timeout to initialize or config BackgroundGeolocation ?
I was checking android-permissions dependency of this library and I found this old issue: https://github.com/nishkarsh/android-permissions/issues/16
Is there something similar with current issue ?
Is there something similar with current issue ?
No, it’s unrelated.
I suggest you install the latest version. You are the only person reporting this issue.
let me know if you know how to reproduce it.
This issue is stale because it has been open for 30 days with no activity.
This issue was closed because it has been inactive for 14 days since being marked as stale.