从错误的线程

时间:2016-10-31 14:58:19

标签: android realm

我有一个LoginActivity的应用程序,当用户正确登录时,我会注册接收消息。 LoginActivity跳转到MainActivity。 到达的消息应该存储在数据库(Realm)中,以便从Main中的Realm实例中恢复。

但是当消息到达时崩溃领域发起这个错误:

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)

我对Realm的工作原理有点迷失,我不知道如何在没有崩溃的情况下跨应用程序访问领域,并继续存储来自LoginActivity的收到的消息。一些帮助,或实现这一目标的方法?

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();
    }

需要的图片:

enter image description here

4 个答案:

答案 0 :(得分:18)

  

Realm从错误的线程访问。 只能访问Realm对象   在他们创建的主题上

此错误消息非常明显。

我看到您通过在UI线程上调用realm来初始化Realm.getDefaultInstance()

错误来自newMessageReceived(),所以我猜这个方法是从后台线程调用的。

在后台线程上获取Realm实例并使用它而不是全局实例:

@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());
        }
    });
}

,如果您想出于某种原因坚持使用全局Realm实例,请确保通过调用runOnUiThread()在UI线程上执行您的代码(或通过Runnable直接将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());
                }
            });
        }
    });
}

答案 1 :(得分:1)

在事务之前分配实例并在事务完成后立即释放它,因此您将没有linegring连接,并且通过这样做,您可以从线程调度程序执行节省。 我使用“数据访问对象”接口进行数据操作,并使用Realm实现该接口。不要使用'transaction async',同步使用所有调用,而是从后台线程对'data access object'执行调用。很好的解决方案 - rxJava库。 只需获取并释放Realm实例 - 库使其便宜。

答案 2 :(得分:1)

每次您要访问数据库时只需创建Realm backgroundRealm = Realm.getDefaultInstance(),不要忘记使用realm.close()关闭数据库

答案 3 :(得分:0)

我还没有使用Realm。但我从错误消息中理解的是,当Loginactivity死亡时,ConnectionConnectResponse可能仍然存在。所以你应该将Realm实例作为参数传递到

newMessageReceived(Realm realm, final ChatMessage message)

并将所有Realm init代码放在触发此方法的类中。