Search code examples
androidandroid-recyclerviewrealmrealm-list

Properly updating RealmModel after onClick without blocking the UI in Android


I have a RecyclerView which displays items from a Realm database. To do so I have implemented a RealmRecyclerViewAdapter based on the realm-android-adapters which gets an OrderedRealmCollection passed in. For this I load the data with findAllAsync()

realm.where(Entry.class).findAllAsync()

When the user scrolls through the list he has the option to "favorite" some of the entries, which I have implemented with a normal OnClickListener on the "favorite" button.

Now I would love to update the "favorite" boolean of the entry whenever the user clicks the button. After the user clicked, a small animation is shown on the button.

For this I tried the following which sadly gives a wrong thread exception:

realm.executeTransactionAsync(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
        entry.setLiked(!entry.isLiked());
    }
});

As an alternative I tried it with the normal executeTransaction which will work, but prevent the animation from being shown.

realm.executeTransaction(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
        entry.setLiked(!entry.isLiked());
    }
});

As an interesting addition this gives the following log:

Mixing asynchronous queries with local writes should be avoided. Realm will convert any async queries to synchronous in order to remain consistent. Use asynchronous writes instead.

Is there any possibility to update the item completely async without introducing lag or preventing the animation from being shown?


Solution

  • RealmRecyclerViewAdapter calls adapter.notifyDataSetChanged() when your Realm gets auto-updated, so the layout animation won't be called.

    As for actually doing the change,

    public class EntryViewHolder extends RecyclerView.ViewHolder {
        @BindView(R.id.entry_favorite)
        Button favButton;
    
        public EntryViewHolder(View view) {
            super(view);
            ButterKnife.bind(this, view);
        }
    
        public void bind(Entry entry) {
            final long entryId = entry.getId();
            favButton.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View view) {
                     realm.executeTransactionAsync(new Realm.Transaction() {
                         @Override
                         public void execute(Realm realm) {
                             Entry entry = realm.where(Entry.class)
                                                .equalTo("id", id)
                                                .findFirst();
                             if(entry != null) {
                                 entry.deleteFromRealm();
                             }
                         }
                     });
                 }
            });
        }
    }