studio - Error de "acceso desde el subproceso incorrecto al usar código compartido entre IntentService y AsyncTask(Android)
intentservice example (3)
Tengo un código que descarga el JSON de un objeto "Actual". Pero este mismo código debe ser llamado por un IntentService cada vez que suena una alarma (cuando la aplicación no está ejecutando ninguna interfaz de usuario), y también por un AsyncTask mientras la aplicación se está ejecutando.
Sin embargo, recibí un error diciendo que el Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.
Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.
Sin embargo, no entiendo cómo o por qué esta traza de pila se puso en un hilo diferente.
Pude deshacerme del error al copiar todo el código compartido y onHandleIntent
directamente en el método onHandleIntent
de onHandleIntent
, pero es muy descuidado y estoy buscando una mejor solución que no requiera duplicar el código.
¿Cómo puedo deshacerme de este error, sin duplicar el código? Gracias.
public class DownloadDealService extends IntentService
{
...
@Override
protected void onHandleIntent(Intent intent)
{
Current todaysCurrent = Utils.downloadTodaysCurrent(); //<--- included for background info
String dateString = Utils.getMehHeadquartersDate(); //(omitted)
Utils.onDownloadCurrentCompleteWithAlarm(todaysCurrent, dateString); //<------ calling this...
}
}
public class Utils
{
// ...other methods ommitted...
//This method is not in the stack trace, but I included it for background information.
public static Current downloadTodaysCurrent()
{
//Set up Gson object... (omitted)
//Set up RestAdapter object... (omitted)
//Set up MehService class... (omitted)
//Download "Current" object from the internet.
Current current = mehService.current(MehService.API_KEY);
return current;
}
//Included for background info- this method is not in the stack trace.
public static void onDownloadCurrentComplete(Current result, String dateString)
{
if(result.getVideo() == null)
{
Log.e("HomePage", "Current was not added on TaskComplete");
return;
}
remainder(result, dateString);
}
public static void onDownloadCurrentCompleteWithAlarm(Current result, String dateString)
{
//Set alarm if download failed and exit this function... (omitted)
remainder(result, dateString);//<------ calling this...
Utils.sendMehNewDealNotification(App.getContext());
}
public static void remainder(Current result, String dateString)
{
Realm realm = RealmDatabase.getInstance();
//Add "Current" to Realm
Current current = Utils.addCurrentToRealm(result, realm); //<------ calling this...
}
public static Current addCurrentToRealm(Current current, Realm realm)
{
realm.beginTransaction(); //<---- Error is here
Current result = realm.copyToRealmOrUpdate(current);
realm.commitTransaction();
return result;
}
}
Rastreo de pila:
E/AndroidRuntime: FATAL EXCEPTION: IntentService[DownloadDealService]
Process: com.example.lexi.meh, PID: 13738
java.lang.IllegalStateException: Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.
at io.realm.Realm.checkIfValid(Realm.java:191)
at io.realm.Realm.beginTransaction(Realm.java:1449)
at com.example.lexi.meh.Utils.Utils.addCurrentToRealm(Utils.java:324)
at com.example.lexi.meh.Utils.Utils.remainder(Utils.java:644)
at com.example.lexi.meh.Utils.Utils.onDownloadCurrentCompleteWithAlarm(Utils.java:635)
at com.example.lexi.meh.Home.DownloadDealService.onHandleIntent(DownloadDealService.java:42)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.os.HandlerThread.run(HandlerThread.java:61)
Tengo una AsyncTask que también llama a algunos de esos métodos de Utils:
public class DownloadAsyncTask extends AsyncTask<Void, Integer, Current>
{
// ... (more methods ommitted)...
protected Current doInBackground(Void... voids)
{
return Utils.downloadTodaysCurrent(); //<---- shared Utils method
}
}
//Async class''s callback in main activity:
public class HomePage extends AppCompatActivity implements DownloadAsyncTaskCallback, DownloadAsyncTaskGistCallback<Current, String>
{
// ... (more methods ommitted)...
public void onTaskComplete(Current result, String dateString)
{
Utils.onDownloadCurrentComplete(result, dateString);
}
}
El problema es que estás llamando a métodos de diferentes hilos, tienes que usar el mismo hilo, crea tu propio HandlerThread.
Si usa el Reino en IntentService, usará el nuevo Reino .por ejemplo
Realm.getInstance(RealmConfiguration config)
Usé el Reino en IntentService
@Override
protected void onHandleIntent(Intent intent) {
Realm realm = Realm.getDefaultInstance();
...
realm.close(); // important on background thread
}
[ACTUALIZADO] basado en la información adicional
RealmDatabase.getInstance () estaba devolviendo la instancia de Realm creada en el hilo principal. Y esta instancia fue utilizada en el hilo de IntentService. Lo que llevó al accidente.
Las instancias de reino no se pueden usar en ningún otro hilo, excepto en el que se crearon.
No puedes pasar objetos de reino entre los hilos. Lo que puede hacer es pasar un identificador único del objeto (es decir, @PrimaryKey), y luego obtener el objeto por su id en otro hilo. Así: realm.where (YourRealmModel.class) .equalTo ("primaryKeyVariable", id) .findFirst ().
Para más detalles, consulte la documentación oficial de Realm y el ejemplo:
- Uso de un reino en todos los subprocesos https://realm.io/docs/java/latest/#threading
- Ejemplo de tema https://github.com/realm/realm-java/tree/master/examples/threadExample