update room android realm

android - room - Acceso al reino desde un hilo incorrecto



realm vs room (4)

Tengo una aplicación con LoginActivity , que cuando el usuario inicia sesión correctamente, me registro para recibir mensajes. Y el LoginActivity salta a MainActivity . Se supone que los mensajes que llegan se almacenan en la base de datos (Realm), para recuperarse de una instancia de Realm en Main.

Pero cuando llega el mensaje, se bloquea el reino lanzando este error:

Exception in packet listener java.lang.IllegalStateException: Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created. at io.realm.BaseRealm.checkIfValid(BaseRealm.java:383) at io.realm.Realm.executeTransactionAsync(Realm.java:1324) at io.realm.Realm.executeTransactionAsync(Realm.java:1276) at es.in2.in2tant.LoginActivity.newMessageReceived(LoginActivity.java:124) at es.in2.in2tant.Connection.Connection$4$1.processMessage(Connection.java:227) at org.jivesoftware.smack.chat.Chat.deliver(Chat.java:180) at org.jivesoftware.smack.chat.ChatManager.deliverMessage(ChatManager.java:351) at org.jivesoftware.smack.chat.ChatManager.access$300(ChatManager.java:53) at org.jivesoftware.smack.chat.ChatManager$2.processPacket(ChatManager.java:162) at org.jivesoftware.smack.AbstractXMPPConnection$4.run(AbstractXMPPConnection.java:1126) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) at java.lang.Thread.run(Thread.java:818)

Estoy un poco perdido en cómo funciona Realm, y no sé cómo hacer que el reino sea accesible en toda la aplicación sin LoginActivity y seguir almacenando los mensajes recibidos de LoginActivity . ¿Alguna ayuda, o enfoques para lograr esto?

LoginActivity.java :

public class LoginActivity extends AppCompatActivity implements ConnectionConnectResponse { ..... protected void onCreate(Bundle savedInstanceState) { //Realm Init config: Realm.init(this); RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().build(); Realm.deleteRealm(realmConfiguration); // Clean slate Realm.setDefaultConfiguration(realmConfiguration); // Make this Realm the default @Override public void newMessageReceived(final ChatMessage message) { Logger.d("NEWMESSAGERECEIVED :" + message); realm.executeTransactionAsync(new Realm.Transaction() { @Override public void execute(Realm realm) { Message receivedMessage = realm.createObject(Message.class, message.id); receivedMessage.setBodyMessage(message.message); receivedMessage.setFrom(message.from); receivedMessage.setTo(message.to); receivedMessage.setDelivered(false); receivedMessage.setMine(false); receivedMessage.setDate(Calendar.getInstance().getTime()); } }); //Logger.d("NEWMESSRE: LAST MESSAGE:" + realm.where(Message.class).equalTo("chatID", message.id)); } @Override protected void onStart() { super.onStart(); realm = Realm.getDefaultInstance(); } @Override protected void onStop() { super.onStop(); realm.close(); }

Imagen de lo que se necesita:


Acceso al reino desde hilo incorrecto. Solo se puede acceder a los objetos del reino en el hilo que se crearon .

Este mensaje de error es bastante autoexplicativo.

Como veo, estás inicializando el realm llamando a Realm.getDefaultInstance() en el subproceso de la interfaz de usuario.

El error proviene de newMessageReceived() , así que supongo que el método se llama desde un subproceso en segundo plano.

Obtenga una instancia de Realm en el subproceso de fondo y use eso en lugar de la instancia global:

@Override public void run () { Realm backgroundRealm = Realm.getDefaultInstance(); backgroundRealm.executeTransactionAsync(new Realm.Transaction() { @Override public void execute(Realm realm) { Message receivedMessage = realm.createObject(Message.class, message.id); receivedMessage.setBodyMessage(message.message); receivedMessage.setFrom(message.from); receivedMessage.setTo(message.to); receivedMessage.setDelivered(false); receivedMessage.setMine(false); receivedMessage.setDate(Calendar.getInstance().getTime()); } }); }

O , si desea mantener la instancia de Realm global por alguna razón, entonces asegúrese de que su código se ejecute en el hilo de la interfaz de usuario llamando a runOnUiThread() (o publicando directamente un Runnable en la cola de mensajes del hilo principal a través de un Handler ):

@Override public void newMessageReceived(final ChatMessage message) { runOnUiThread(new Runnable() { @Override public void run() { realm.executeTransactionAsync(new Realm.Transaction() { @Override public void execute(Realm realm) { Message receivedMessage = realm.createObject(Message.class, message.id); receivedMessage.setBodyMessage(message.message); receivedMessage.setFrom(message.from); receivedMessage.setTo(message.to); receivedMessage.setDelivered(false); receivedMessage.setMine(false); receivedMessage.setDate(Calendar.getInstance().getTime()); } }); } }); }


Asigne la instancia antes de la transacción y libérela justo después de que se complete la transacción, de modo que no tenga una conexión de linegring y, al hacerlo, obtendrá ahorros del programador de hilos. Utilizo la interfaz ''Objeto de acceso a datos'' para manipulaciones con datos y esa interfaz se implementa utilizando Realm. No use ''transacción asíncrona'', use todas las llamadas de forma síncrona, pero realice llamadas en el ''objeto de acceso a datos'' desde el hilo de fondo. Buena solución para eso - biblioteca rxJava. Simplemente obtenga y libere la instancia de Realm todo el tiempo: la biblioteca lo hace barato.


No he usado Realm todavía. Pero lo que entendí por el mensaje de error es que ConnectionConnectResponse puede estar vivo cuando el Loginactivity muera. Entonces deberías pasar la instancia de Realm como un parámetro dentro

newMessageReceived(Realm realm, final ChatMessage message)

y ponga todo el código de inicio de Reino en la clase en la que dispare este método.


Simplemente cree Realm backgroundRealm = Realm.getDefaultInstance() cada vez que quiera acceder a la base de datos y no olvide cerrarla utilizando realm.close()