Realm和Retrofit,如何在UI线程外保存?
Realm and Retrofit, how to save outside the UI thread?
我正在使用 Retrofit to download a json
of Client
s, I then have to persist them with Realm(Client
扩展 RealmObject
)。问题是我有 15k Client
s,所以保存需要几秒钟。如果我无法在线程之间传递 RealmObject
,如何将我从 Retrofit
获得的客户端列表传递给 background thread
?
这是我现在拥有的代码,它会在我执行保存时阻止 UI 几秒钟。
api.clients(token, date, new Callback<List<Client>>() {
new Callback<LoginResponse>() {
@Override
public void success(List<Client> clients, Response response) {
Logs.retrofit("Clients status: " + response.getStatus());
if (response.getStatus() == 200) {
//It's all good man!
saveClients(clients);
if (callbacks != null) callbacks.onClientListDownloadSuccessful();
} else if (response.getStatus() == 401) {
//Wrong token, refresh it and retry
refreshLoginToken();
} else {
//Other error status
if (callbacks != null)
callbacks.onClientListDownloadError(response.getStatus());
}
}
@Override
public void failure(RetrofitError error) {
Logs.retrofit("Client error: " + error.getMessage());
if (error.getResponse() != null && error.getResponse()
.getStatus() == 401) {
refreshLoginToken();
} else if (callbacks != null) callbacks.onClientListDownloadError(0);
}
private void saveClients(List<Client> clients) {
Logs.realm("Saving clients to local db: " + clients.size());
Realm realm = App.getCommercialiRealm(context);
List<Long> ids = new ArrayList<>();
realm.beginTransaction();
for (Client client : clients) {
if (client.isDeleted()) {
//Delete client
ids.add(client.getID());
}
}
//Add or update clients
realm.copyToRealmOrUpdate(clients);
Logs.realm("Client in db " + realm.where(Client.class)
.count());
//Delete clients
deleteClients(realm, ids);
Logs.realm("Client in db after cleanup " + realm.where(Client.class)
.count());
realm.commitTransaction();
PrefsUtils.saveLastSync(context, System.currentTimeMillis());
}
就我个人而言,我会尽量让我的服务层和持久层分离。解析对作为简单 POJO 实现的客户端 class 的网络响应,并仅在处理数据库时使用 RealmObjects(您需要在两个 'client' 实体之间使用某种映射实用程序)。
如果您真的想将 Retrofit 响应用作 RealmObjects,您可能需要在 API 界面中删除 'Callback' 格式并实施您自己的线程解决方案,以便 Retrofit 和领域操作在同一个线程中执行。
基本上,设置它以便您可以执行如下操作:
try {
List<Client> clients = api.clients(token, date);
saveClients(clients);
} catch(RetrofitError e){
Response response = e.getResponse();
if (response.getStatus() == 401) {
// Wrong token, refresh it and retry
refreshLoginToken();
} else {
// Propagate error on the UI thread or whatever :P
}
}
在后台线程中。
我正在使用 Retrofit to download a json
of Client
s, I then have to persist them with Realm(Client
扩展 RealmObject
)。问题是我有 15k Client
s,所以保存需要几秒钟。如果我无法在线程之间传递 RealmObject
,如何将我从 Retrofit
获得的客户端列表传递给 background thread
?
这是我现在拥有的代码,它会在我执行保存时阻止 UI 几秒钟。
api.clients(token, date, new Callback<List<Client>>() {
new Callback<LoginResponse>() {
@Override
public void success(List<Client> clients, Response response) {
Logs.retrofit("Clients status: " + response.getStatus());
if (response.getStatus() == 200) {
//It's all good man!
saveClients(clients);
if (callbacks != null) callbacks.onClientListDownloadSuccessful();
} else if (response.getStatus() == 401) {
//Wrong token, refresh it and retry
refreshLoginToken();
} else {
//Other error status
if (callbacks != null)
callbacks.onClientListDownloadError(response.getStatus());
}
}
@Override
public void failure(RetrofitError error) {
Logs.retrofit("Client error: " + error.getMessage());
if (error.getResponse() != null && error.getResponse()
.getStatus() == 401) {
refreshLoginToken();
} else if (callbacks != null) callbacks.onClientListDownloadError(0);
}
private void saveClients(List<Client> clients) {
Logs.realm("Saving clients to local db: " + clients.size());
Realm realm = App.getCommercialiRealm(context);
List<Long> ids = new ArrayList<>();
realm.beginTransaction();
for (Client client : clients) {
if (client.isDeleted()) {
//Delete client
ids.add(client.getID());
}
}
//Add or update clients
realm.copyToRealmOrUpdate(clients);
Logs.realm("Client in db " + realm.where(Client.class)
.count());
//Delete clients
deleteClients(realm, ids);
Logs.realm("Client in db after cleanup " + realm.where(Client.class)
.count());
realm.commitTransaction();
PrefsUtils.saveLastSync(context, System.currentTimeMillis());
}
就我个人而言,我会尽量让我的服务层和持久层分离。解析对作为简单 POJO 实现的客户端 class 的网络响应,并仅在处理数据库时使用 RealmObjects(您需要在两个 'client' 实体之间使用某种映射实用程序)。
如果您真的想将 Retrofit 响应用作 RealmObjects,您可能需要在 API 界面中删除 'Callback' 格式并实施您自己的线程解决方案,以便 Retrofit 和领域操作在同一个线程中执行。
基本上,设置它以便您可以执行如下操作:
try {
List<Client> clients = api.clients(token, date);
saveClients(clients);
} catch(RetrofitError e){
Response response = e.getResponse();
if (response.getStatus() == 401) {
// Wrong token, refresh it and retry
refreshLoginToken();
} else {
// Propagate error on the UI thread or whatever :P
}
}
在后台线程中。