Моему приложению нужно запускать геозоны в фоновом режиме (приложение закрыто), поэтому я создал класс с JobIntentService, чтобы запустить это геозону, но когда срабатывает какая-то геозона, приложение должно прочитать базу данных firebase и поэтому происходит сбой приложения с помощью этого logcat:
--------- beginning of crash
2018-10-07 09:02:33.952 11623-14893/com.app.GNV E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.app.GNV, PID: 11623
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:318)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:762)
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
at com.google.firebase.database.zza.<init>(com.google.firebase:firebase-database@@16.0.2:1024)
at com.google.firebase.database.obfuscated.zzb.zza(com.google.firebase:firebase-database@@16.0.2:77)
at com.google.firebase.database.obfuscated.zzu.zza(com.google.firebase:firebase-database@@16.0.2:2234)
at com.google.firebase.database.obfuscated.zzad.zzb(com.google.firebase:firebase-database@@16.0.2:92)
at com.google.firebase.database.obfuscated.zzad.zza(com.google.firebase:firebase-database@@16.0.2:42)
at com.google.firebase.database.FirebaseDatabase.zza(com.google.firebase:firebase-database@@16.0.2:357)
at com.google.firebase.database.FirebaseDatabase.getReference(com.google.firebase:firebase-database@@16.0.2:188)
at com.app.GNV.Service.GeofenceNotification.displayNotification(GeofenceNotification.java:44)
at com.app.GNV.Service.GeofenceTransitionsJobIntentService.onHandleWork(GeofenceTransitionsJobIntentService.java:61)
at android.support.v4.app.JobIntentService$CommandProcessor.doInBackground(JobIntentService.java:392)
at android.support.v4.app.JobIntentService$CommandProcessor.doInBackground(JobIntentService.java:383)
at android.os.AsyncTask$2.call(AsyncTask.java:304)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:762)
Я думаю, проблема была в том, что JobIntentService запускается в фоновом потоке, а firebase не работает в фоновом потоке.Может быть, мне нужно использовать другой способ для чтения базы данных Firebase ... любое предложение?
Примечание: приложение должно быть закрыто и запускать геозоны в фоновом режиме.
GeofenceTransitionJobIntentService.class
public class GeofenceTransitionsJobIntentService extends JobIntentService {
private static final int JOB_ID = 2018;
private static final String TAG = "GeofenceTransitionsIS";
public static void enqueueWork(@NonNull Context context, Intent intent) {
enqueueWork(context, GeofenceTransitionsJobIntentService.class, JOB_ID, intent);
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
// Initialize SharedPreferences editor
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
SharedPreferences.Editor editor = sharedPreferences.edit();
// Carrega coordenadas atual e do ultimo abastecimento registrado
boolean cfgSaiuDoPosto = sharedPreferences.getBoolean("CfgSaiuDoPosto", false);
boolean cfgTempoMinimo = sharedPreferences.getBoolean("CfgTempoMinimo", false);
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
String errorMessage = GeofenceErrorMessages.getErrorString(this, geofencingEvent.getErrorCode());
Log.e(TAG, errorMessage);
return;
}
int transitionType = geofencingEvent.getGeofenceTransition();
if (transitionType == Geofence.GEOFENCE_TRANSITION_DWELL || transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
for (Geofence geofence : triggeringGeofences) {
switch (transitionType) {
case Geofence.GEOFENCE_TRANSITION_DWELL:
String mPostoID = geofence.getRequestId();
long dataNofif = System.currentTimeMillis();
if ( cfgTempoMinimo && cfgSaiuDoPosto ) {
GeofenceNotification geofenceNotification = new GeofenceNotification(this);
geofenceNotification.displayNotification(mPostoID, dataNofif);
Log.w(TAG,"Notificando possível abastecimento");
}
break;
case Geofence.GEOFENCE_TRANSITION_EXIT:
editor.putBoolean("CfgGeofencesAdded", false).apply();
Log.w(TAG,"Reiniciando GeofenceService pois saiu do raio de MasterGeo");
// Restart GeofenceService
GeofencesDataSource gds = new GeofencesDataSource(getApplicationContext());
gds.CarregaGeofenceService();
break;
}
}
} else {
// Log the error.
Log.e(TAG, getString(R.string.geofence_transition_invalid_type, transitionType));
}
}
}
GeofenceNotification.class
public class GeofenceNotification {
private static final String TAG = "GeofenceNotification";
private static final Integer NOTIFICATION_ID = 99;
protected Context context;
private static NotificationManager mNotificationManager;
private static AlarmManager alarmManager;
GeofenceNotification(Context context) {
this.context = context;
mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
void displayNotification(final String postoID, final long dataNotif) {
DatabaseReference mPostosDBRef = Utils.getDatabase().getReference().child("postos");
mPostosDBRef.child(postoID).addListenerForSingleValueEvent(new ValueEventListener() {
public void onDataChange(@NonNull DataSnapshot dtSnap) {
String mNome = "Nome do posto";
if (dtSnap.exists()) { mNome = dtSnap.child("nome").getValue(String.class); }
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
boolean cfgNotif = sharedPreferences.getBoolean("CfgNotif", true);
if (cfgNotif) {
startNotification(context, postoID, mNome, dataNotif);
} else {
gravaAbastecimento(context, postoID, dataNotif);
}
}
public void onCancelled(@NonNull DatabaseError databaseError) {
Log.e(TAG,"****** The read failed: " + databaseError);
}
});
}
//... some irrelevant code ...
}
OK