我在Realm for Android中有一些缺少功能的问题。我理解首选模式并不真正需要LIMIT类型的函数,但我有一个非常具体的用例,我没有看到使用当前API的直接解决方案。
我有一个Realm,我在其中保存LogMessage对象。封闭的应用程序可以调用sendLog()
方法,该方法将向Realm添加新的LogMessage。
该应用还可以批量将这些LogMessage同步到服务器,并删除已同步的那些。现在问题出在这里:
假设我获得所有LogMessages并希望以100个批次同步它们:
Realm realm = Realm.getInstance(realmConfiguration);
RealmResults<LogMessage> result = realm.where(LogMessage.class).findAll();
int resultSize = result.size();
int logsPerRequest = 100;
while(result.size() > 0) {
final List<LogMessage> pageResult = result.subList(0 , Math.min(logsPerRequest, resultSize));
JsonObject json = new JsonObject();
JsonElement array = gson.toJsonTree(pageResult, new TypeToken<List<LogMessage>>(){}.getType());
json.add("events", array);
RequestBody body = RequestBody.create(JSON, json.toString());
Request request = new Request.Builder()
.url(extras.getString(URL, ""))
.post(body)
.build();
//Try to sync
final Response response = client.newCall(request).execute();
if (response != null && response.isSuccessful() && response.body() != null) {
//Delete the synced log messages
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
//WHAT NOW?
}
});
}
}
您可以看到问题所在。我不能只在deleteFromRealm()
上调用pageResult
,因为它是一个非托管列表。也没有方法可以在领域本身调用deleteFromRealm()
并传入要删除的对象列表。
我无法在deleteFromRealm()
上拨打result
因为这会删除整个列表,而我可能还有LogMessages要同步。
我怎样才能最好地解决这个问题?
答案 0 :(得分:0)
一种可能性是将整个逻辑移动到单个事务中,从而确保Realm实例和RealmResults在请求时是最新的
Realm realm = null;
try {
realm = Realm.getInstance(realmConfiguration);
realm.executeTransaction(new Realm.Transaction() {
public void execute(Realm realm) {
int logsPerRequest = 100;
while(realm.where(LogMessage.class).count() > 0) {
RealmResults<LogMessage> result = realm.where(LogMessage.class).findAll();
final List<LogMessage> pageResult = result.subList(0, Math.min(logsPerRequest, result.size()));
JsonObject json = new JsonObject();
JsonElement array = gson.toJsonTree(pageResult, new TypeToken<List<LogMessage>>() {}.getType());
json.add("events", array);
RequestBody body = RequestBody.create(JSON, json.toString());
Request request = new Request.Builder().url(extras.getString(URL, "")).post(body).build();
//Try to sync
final Response response = client.newCall(request).execute();
if(response != null && response.isSuccessful() && response.body() != null) {
//Delete the synced log messages
for(int i = pageResult.size()-1; i >= 0; i--) {
LogMessage message = pageResult.get(i);
message.deleteFromRealm();
}
}
}
}
}
} finally {
if(realm != null) {
realm.close();
}
}
另一种可能性是(叹息......我不喜欢推荐这种方法)通过内部API(v1.2.0)为代码添加强制刷新。
package io.realm; // <---- this is important
public class RealmRefresh {
public static void refreshRealm(Realm realm) {
Message message = Message.obtain();
msg.what = HandlerControllerConstants.LOCAL_COMMIT;
realm.handlerController.handleMessage(msg);
}
}
你可以做什么
Realm realm = null;
try {
realm = Realm.getInstance(realmConfiguration);
RealmRefresh.refreshRealm(realm);
int logsPerRequest = 100;
while(realm.where(LogMessage.class).count() > 0){
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
RealmResults<LogMessage> result = realm.where(LogMessage.class).findAll();
final List<LogMessage> pageResult = result.subList(0, Math.min(logsPerRequest, result.size()));
JsonObject json = new JsonObject();
JsonElement array = gson.toJsonTree(pageResult, new TypeToken<List<LogMessage>>() {}.getType());
json.add("events", array);
RequestBody body = RequestBody.create(JSON, json.toString());
Request request = new Request.Builder().url(extras.getString(URL, "")).post(body).build();
//Try to sync
final Response response = client.newCall(request).execute();
if(response != null && response.isSuccessful() && response.body() != null) {
//Delete the synced log messages
for(int i = pageResult.size() - 1; i >= 0; i--) {
LogMessage message = pageResult.get(i);
message.deleteFromRealm();
}
}
}
});
RealmRefresh.refreshRealm(realm);
}
} finally {
if(realm != null) {
realm.close();
}
}
尽管我不喜欢修补内部API,但这对我来说似乎更加强大。