Android realm gives outdated results in multithreading scenarios

situation

I have a typical UI thread and worker thread scheme. I do some work and write the results to the fields in the worker thread. The result is a simple realobject with some string fields. After this operation, I send the events on the UI thread to my activity (using Otto event bus) to report that the work has been completed

After receiving an event in my activity, I will query the result, and the string field is not updated with the written value

On worker threads:

// Did some work. Got some result

// Write to realm
try {
    realm = Realm.getDefaultInstance();

    realm.executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            MyResult result = realm.where(MyResult.class)
                .equalTo("id", 1)
                .findFirst();
            result.someString = "hello world";
        }
    });
} finally {
    if(realm != null){
        realm.close();
        realm = null;                    
    }
}

//Post job done event on Otto bus
uiThreadBus.post(new JobDoneEvent());

During the activity:

// Upon received JobDoneEvent
MyResult result = realm.where(MyResult.class)
    .equalTo("id", 1)
    .findFirst();

// result.someString is some stale value
Log.d("TAG", result.someString);

What did I do?

I realized that if I wrap the query in a transaction block, realmobject will be up to date when I try to print the query

// Upon received JobDoneEvent
MyResult result = null;
try{
    realm.beginTransaction();
    result = realm.where(MyResult.class)
        .equalTo("id", 1)
        .findFirst();
    realm.cancelTransaction();
}
catch(Exception e) {
    realm.cancelTransaction();
}    

// result.someString is up-to-date
Log.d("TAG", result.someString);

problem

>What is the correct way to get the latest realmobject? Do I have to put them into a transaction block every time to force it to "synchronize" with the worker thread? Is there a pattern to follow? > What exactly does it do to start a domain transaction (through real #begintransaction() or real #executetransaction())? Does it prevent other threads from making read / write attempts? Is there any harm in performing long operations (such as network requests) in transactions?

edit

Actual code:

// Did some work. Got some result

// Write to realm
try {
    realm = Realm.getDefaultInstance();
    realm.executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            User managedUser = result.payload.createOrUpdateInRealm(realm, 
                MyApplication.getPrimaryKeyFactory());

                Log.i("TAG", "updated user: " + managedUser.getId());
            }
        });
} finally {
    if(realm != null) {
        realm.close();
        realm = null;
    }
}

//Post job done event on Otto bus
MyApplication.getBusInstance().post(new LoginEvent());



// Writing to realm method
public User createOrUpdateInRealm(@NonNull Realm realm,
                                  @NonNull PrimaryKeyFactory pkFactory) {
    User managedUser = realm.where(User.class)
            .equalTo("primary_key", pk)
            .findFirst();

    managedUser.setId(xUserId);
    return managedUser;
}


// Event receiving method in Activity
@Subscribe
public void loginEventReceived(LoginEvent event) {
    User user = mRealm.where(User.class)
        .equalTo("primary_key", mPk)
        .findFirst();

    Log.d("TAG", user.getId()); 
}

resolvent:

The domain uses a special "listener" thread to communicate with other threads, which puts the message into the looper queue of the UI thread. We will not provide any guarantee, because it may be delayed for many reasons. Otto will send a message directly, which is likely to occur before the loopback message arrives. In this case, the data on the UI thread will be displayed as "stale"

For these types of notifications, it is best to use realm to change the listener. In this case, you will be notified when the data is ready

See also: https://github.com/realm/realm-java/issues/3427

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>