我在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。
答案 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