Android Realm for-loop - 在循环期间删除RealmResults

时间:2017-06-05 19:47:45

标签: android realm

我在IntentService中运行了一些代码,进行图片上传。它首先获取“排队”上传的帖子,然后循环播放这些帖子并进行同步Retrofit调用以上传图像。非常坦率的。请参阅代码以供参考:

final RealmResults<Post> posts = realm.where(Post.class)
            .equalTo("uniqueCode", uniqueCode)
            .equalTo("queued", true)
            .isEmpty("url")
            .findAll();

Log.d(TAG, "post count: " + posts.size());

if (posts != null && posts.size() > 0) {
    for (int i = 0; i < posts.size(); i++) {
        Log.d(TAG, "posts count now: " + posts.size());

        Post post = posts.get(i);

        Post submittedPost = api.uploadPhoto(<params>); // Retrofit call, which works fine

        if (submittedPost != null) {
            realm.beginTransaction();
            post.setQueued(false);
            post.setUrl(submittedPost.getUrl());
            realm.commitTransaction();

            sendBroadcastUpdate(); // This updates the UI in places
        }
    }
}

奇怪的是,每次进入for循环时,结果的大小(在我上面的情况下为“post”)下降了一个 - 这是由我的Log输出确认的,每次递减一次,所以它只能通过一些结果。这几乎就像每次我在循环期间提交Realm事务时,它正在更新我获取的查询结果,即使该数组被设置为final。

我确认如果我没有设置这些值('排队'和'url'),它就不会这样做。这告诉我它以某种方式更新结果。我尝试了不同的东西,比如一个while循环(即“while(posts.size()&gt; 0)”),但它通过2-3个,然后突然大小“帖子“立即为0,完全没有理由我能看到。

我也尝试在循环之前和之后进行开始/提交,但它产生类似的结果。如果我在处理之前将其转换为数组也是如此。它似乎总是通过它们中的一些,然后大小自动设置为0,因此它退出循环。

这让我觉得非常离奇,特别是因为我将结果设置为“最终” - 这是预期的行为吗?有没有人知道这种方法,偶然?

供参考,我们使用的是Realm版本:0.86。

2 个答案:

答案 0 :(得分:2)

在版本&lt; 0.89.0或版本&gt; = 3.0.0 *,这是预期的行为(见here)。

RealmResults是对数据库的最新版本的视图(对于满足给定条件的给定对象类型),并且事务本质上是“创建数据库的最新版本”,意味着{{1每次修改都会开始看到新的修改过的数据。

见以下内容:

RealmResults

在创建交易时,您会开始看到最新版本,在这种情况下,final RealmResults<Post> posts = realm.where(Post.class) .equalTo("uniqueCode", uniqueCode) .equalTo("queued", true) // <---- condition true .isEmpty("url") .findAll(); ... if (submittedPost != null) { realm.beginTransaction(); post.setQueued(false); // <---- condition false post.setUrl(submittedPost.getUrl()); realm.commitTransaction(); sendBroadcastUpdate(); // This updates the UI in places } 将不再包含RealmResults的元素。

对于Realm 0.88.3或更早版本,您需要反向迭代RealmResults,或者“在结果不为空时进行迭代”(在0.89.0突破性更改之前我使用了这个方法很多,但它再次使用3.0.0+,这样很好)

queued == false

对于Realm 3.0.0+,您可以直接使用realm.refresh(); // enforce the next RealmResults to be *definitely* up-to-date final RealmResults<Post> posts = realm.where(Post.class) .equalTo("uniqueCode", uniqueCode) .equalTo("queued", true) .isEmpty("url") .findAll(); while(!posts.isEmpty()) { Post post = posts.get(0); Post submittedPost = api.uploadPhoto(<params>); // Retrofit call, which works fine if (submittedPost != null) { realm.beginTransaction(); post.setQueued(false); post.setUrl(submittedPost.getUrl()); realm.commitTransaction(); sendBroadcastUpdate(); // This updates the UI in places } } (迭代器)或you can use a collection snapshot

for(Post post : results) {

*(老实说,介于两者之间的行为是一个黑客,其中RealmResults未同步以查看最新版本,3.0.0必须撤消此黑客攻击)

答案 1 :(得分:0)

这是迭代器的正常行为。一旦调用.next(),就会获得该项,并将其从迭代器中删除。如果要保留项目,请编写实用程序以将迭代器转换为ArrayList或类似的东西。您可以在此处阅读有关迭代器的更多信息:https://www.tutorialspoint.com/java/java_using_iterator.htm