Realm DB如何将查询输出对象作为非托管?

时间:2018-01-02 14:34:08

标签: android realm

我正在尝试查询我的Realm DB,以便输出将提供一个非托管对象,为此,我将RealmList类型的对象更改为List

现在,事情是在addchangeListener中我将输出对象(stories)的值设为managed。但stories的类型为List。那么为什么我的stories对象变为managed,它应该作为unmanaged对象。

List<story> stories = realm.where(story.class).findAllAsync();
stories.addChangeListener(new RealmChangeListener<RealmResults<story>>() {
            @Override
            public void onChange(RealmResults<story> storydata) {
                if (storydata.size() != 0) {
                    madapter = new StoriesAdapter(stories, getBaseContext(), MR);
                    mrecyclerview.setNestedScrollingEnabled(false);
                    mrecyclerview.setLayoutManager(new LinearLayoutManager(getBaseContext()));
                    mrecyclerview.setAdapter(madapter);
                }
            }
        });

StoriesAdapter

class StoriesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

       List<story> storyList;

       StoriesAdapter(List<story> storyList) {
           this.storyList = storyList;
       }
 }

我说我的Listmanaged,因为当我尝试编写下面的代码时,我得到Cannot modify managed objects outside of a write transaction.

madapter.storyList.get(3).setTitle("Wonderland"); // where storyList is List which i am pointing to `stories`.

2 个答案:

答案 0 :(得分:1)

  

List<story> stories = realm.where(story.class).findAllAsync();

因为指定类型List<story>只是意味着您会将返回的列表视为List<story>,但从技术上讲,它仍然是RealmResults<story>

  

stories.addChangeListener(new RealmChangeListener<RealmResults<story>>() {

下面的这行甚至不应该编译。

故事应存储在field

private RealmResults<story> stories;

public void ...() {
    stories = ...
    stories.addChangeListener(...

无论如何,所以你正在使用RealmResults,这意味着在

class StoriesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

   List<story> storyList;

您提供的storyListRealmResults<story>,因此调用storyList.get(...)将返回托管的RealmObjects。

托管的RealmObjects是“暂时不可变的”,这意味着它们只能在事务中修改。通常也不建议在UI线程上运行写事务。

最简单的方法是使用realm-android-adapters

class StoriesAdapter extends RealmRecyclerViewAdapter<story, RecyclerView.ViewHolder> {

   StoriesAdapter(OrderedRealmCollection<story> stories) {
       super(stories, true, true);
   }
}

当您想要修改对象时,您可以

story item = getData().get(3);
final String id = item.getId();
realm.executeTransactionAsync(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
        story changedItem = realm.where(story.class).equalTo("id", id).findFirst();
        changedItem.setTitle("Wonderland");
    }
});

然后Realm将处理自动更新RealmResults,story对象和RecyclerView。

编辑:如果您打算使用非托管对象,那么您可以使用realm.copyFromRealm(results),除非在UI线程上进行读取。

您可以创建一个后台循环线程并从那里获取结果,但管理它可能会很棘手。幸运的是,我创建了一个名为Monarchy的库,可以让你做到这一点。

请参阅relevant sample code for how you'd use it

答案 1 :(得分:0)

故事是隐式管理的,原因是RealmResults抽象地扩展了列表界面。这就是为什么铸造是可能的,在RealmResults的相同机制下仍然优先。此外,如果您在RealmResults上注册RealmChangeListener,则应该直接将adapter.notifyDataSetChanged()实例传递给适配器,这将调用<QData> <Measure> some text here <Answer>Answer1</Answer> <Question>Question1</Question> </Measure> <Measure> some text here <Answer>Answer1</Answer> <Question>Question1</Question> </Meaure> </QData> 。否则,写入将更新RealmResults内容,并且您的适配器将被取消同步。

Realm不像SQLite或Core Data。如果您正在使用Realm,请利用实时对象。不要实现任何刷新逻辑或重新查询。始终允许当前类拥有自己的领域查询实例。

事实确实如此,Realm对象和任何子对象都不是线程安全的。它们仅限于一个线程,以确保维护原子权利。有一个内部列表,其中每个线程都有自己唯一的Realm实例。如果你想在一个线程之间传递对象 - 例如,如果你在主线程上创建一个dog对象,将它传递给后台线程,然后尝试访问一个属性 - 它将立即触发一个异常。

此外,您正在使用异步查询,它将其置于工作线程上。