在 onClick 后正确更新 RealmModel 而不会阻塞 Android 中的 UI

Properly updating RealmModel after onClick without blocking the UI in Android

我有一个 RecyclerView,它显示 Realm 数据库中的项目。 为此,我实现了一个基于 realm-android-adaptersRealmRecyclerViewAdapter,它获得了一个 OrderedRealmCollection 传入。 为此,我使用 findAllAsync()

加载数据
realm.where(Entry.class).findAllAsync()

当用户滚动列表时,他可以选择 "favorite" 一些条目,我在 "favorite" 按钮上使用普通 OnClickListener 实现了这些条目。

现在我很乐意在用户单击按钮时更新条目的 "favorite" 布尔值。用户点击后,按钮上会显示一个小动画。

为此,我尝试了以下方法,遗憾的是给出了错误的线程异常:

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

作为替代方案,我使用正常的 executeTransaction 进行了尝试,这会起作用,但会阻止显示动画。

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

作为一个有趣的补充,它给出了以下日志:

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.

是否有可能在不引入延迟或阻止动画显示的情况下完全异步更新项目?

在后台线程上执行此操作。我建议使用经典的 Thread.class 。在新线程外启动动画,并通过 UI 线程上的回调关闭它。

Realm realm = Realm.getInstance(..);
realm.beginTransaction();
YourClass yourClassInstance = realm.where(YourClass.class)
        .equalTo(..)
        .findFirst();
if(yourClassInstance != null){
   yourClassInstance.setLiked(!yourClassInstance.getLiked());
}else{
   yourClassInstance = realm.createObject(YourClass.class);
   yourClassInstance.setLiked(whateverYouWant);
}
realm.commitTransaction();

RealmRecyclerViewAdapter 在您的 Realm 自动更新时调用 adapter.notifyDataSetChanged(),因此不会调用布局动画。

至于实际进行更改,

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