2016-10-31 3 views
12

私はLoginActivityというアプリケーションを持っています。ユーザーが正しくログインすると、メッセージを受信するために登録します。 LoginActivityMainActivityにジャンプします。 到着するメッセージは、データベース(Realm)に格納され、MainのRealmインスタンスからリカバリされると想定されています。不正なスレッドからのレルムアクセス

しかし、メッセージがこのerrrorを起動することクラッシュ分野到着したとき:

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) 

を私はレルムがどのように機能するかに失われたビットだし、私はせずに、アプリケーション間で領域をアクセス可能にする方法がわかりませんクラッシュし、この受信したメッセージを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

答えて

14

不正なスレッドからのレルムアクセス。 レルムオブジェクトは、作成されたスレッド上で にしかアクセスできません

このエラーメッセージは完全にわかりやすいものです。

realmをUIスレッドでRealm.getDefaultInstance()に呼び出して初期化しています。

エラーはnewMessageReceived()から来ているので、そのメソッドはバックグラウンドスレッドから呼び出されると思います。

どちらの代わりにグローバルインスタンスのバックグラウンドスレッドと使用上のRealmインスタンス取得:あなたが作る、その後、何らかの理由でグローバル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()); 
     } 
    }); 
} 

を必ずあなたのコードはrunOnUiThread()を呼び出す(または直接Handlerを介してメインスレッドのメッセージキューにRunnableを掲載する)ことにより、UIスレッド上で実行されます。

@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

は、トランザクションの前にインスタンスを割り当て、右のトランザクションの後にそれを解放完了するので、あなたはしません回線接続があり、スレッドスケジューラから節約を実行します。 データの操作に「データアクセスオブジェクト」インターフェイスを使用し、そのインターフェイスがレルムを使用して実装されています。 'トランザクション非同期'を使用せず、すべての呼び出しを同期的に使用しますが、バックグラウンドスレッドから 'データアクセスオブジェクト'で呼び出しを実行します。その - rxJavaライブラリのための良い解決策。 Realmインスタンスを常に取得してリリースするだけで、ライブラリは安価です。

+0

非同期トランザクションAPIの使用には何も問題ありません。そしてその人はRealmをほとんど知っていません、なぜあなたは彼にRxでフルFRPに行くように言うでしょうか? – EpicPandaForce

+0

1つのトランザクションを実行し、そのトランザクションが完了した後に、書き込みトランザクションまたは一部の読み取りトランザクションを実行する必要があるとします。最初に完了したときにのみ、2番目の操作を開始する必要があります。 async()を使用すると、前回のトランザクションがいつ完了したかを追跡することができなくなります。または、あるスレッド上にオブジェクトを作成し、誤ってそのインスタンスを別のスレッド上で使用すると(スレッドプールを使用して)、エラーが発生します。一方、トランザクションの前にインスタンスを割り当ててトランザクション後に解放すると、それは当てはまりません –

0

私はまだレルムを使用していません。しかし、私がエラーメッセージから理解したことは、LoginConnectivityが死んでいるときにConnectionConnectResponseが生きている可能性があるということです。だから、

newMessageReceived(Realm realm, final ChatMessage message)

内のパラメータとしてレルムインスタンスを渡すと、あなたは、このメソッドを発射クラス内のすべてのレルムのinitコードを置く必要があります。

関連する問題