【问题标题】:Realm DB how to get query output object as unmanaged?Realm DB如何将查询输出对象作为非托管对象?
【发布时间】:2018-01-02 14:34:07
【问题描述】:

我正在尝试查询我的 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`.

【问题讨论】:

  • 在测试期间监听器是否 100% 工作?
  • 是的,但你为什么要问??
  • 谁说它是托管的,它仍然没有托管。
  • 它是被管理的,因为现在当我尝试在我的madapter 中更改List 时,我得到Cannot modify managed objects outside of a write transaction. 这意味着我在我的适配器方法中初始化的列表是managed
  • @Remario 详细说明你的意思? RealmResults 中的元素是懒惰获取的,所以它不应该导致任何“内存问题蔓延到你身上”?什么内存问题?

标签: android realm


【解决方案1】:

List&lt;story&gt; stories = realm.where(story.class).findAllAsync();

因为指定类型 List&lt;story&gt; 只是意味着您将看到返回的列表为 List&lt;story&gt;,但从技术上讲,它仍然是 RealmResults&lt;story&gt;

stories.addChangeListener(new RealmChangeListener&lt;RealmResults&lt;story&gt;&gt;() {

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


故事应该存储在field

private RealmResults<story> stories;

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

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

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

   List<story> storyList;

您提供的这个storyList 是一个RealmResults&lt;story&gt;,所以调用storyList.get(...) 将返回托管的RealmObjects。


Managed 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

【讨论】:

  • 同意,但怎么可能投射?
  • 因为RealmResults&lt;T&gt; implements OrderedRealmCollection&lt;T&gt;OrderedRealmCollection&lt;T&gt; extends List&lt;T&gt;。没有涉及实际的“铸造”。至于addChangeListener,正如我所说,那不应该编译:D
  • 我很惊讶,这是版本的事情吗?
  • 不,我认为这个问题在某种程度上是不正确的。
  • @EpicPandaForce 谢谢,但实际上目前我只想使用非托管对象,你能告诉我如何在查询的输出中获取非托管对象吗??
【解决方案2】:

故事是隐式管理的,原因是RealmResults抽象地扩展了列表接口。这就是为什么可以进行强制转换的原因,在 RealmResults 的相同机制下仍然优先。此外,如果您在其上注册了RealmChangeListener,您应该只将RealmResults 实例直接传递给适配器,这将调用adapter.notifyDataSetChanged()。否则,写入将更新 RealmResults 内容,并且您的适配器将被取消同步。

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

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

您还使用异步查询,将其放在工作线程上。

【讨论】:

  • 为了提供一致性和安全性 Realm 保证,施加了一个简单的约束:所有 Realm、对象、结果和列表都被限制在它们创建的线程中。
  • 即使适配器在您的示例中使用主线程,您仍将内存引用传递给适配器。
  • 了解线程限制不是基于 Realm 内部结构的临时限制或人为约束,而是使编写正确代码更容易的设计的关键部分,这一点很重要。
  • 为了具有隔离性(ACID 中的“I”),不同事务中的更改不会反映在其他事务中,直到这些事务升级到最新版本。这里的关键词是隔离。
  • 您收到此错误是因为故事实际上是一个真实的结果列表,它是被管理的,并且因为它管理的任何写入都需要在提交事务中进行转义。
猜你喜欢
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-16
  • 1970-01-01
  • 1970-01-01
  • 2014-05-07
相关资源
最近更新 更多