I'm using Retrofit to download a json
of Client
s, I then have to persist them with Realm (Client
extends RealmObject
). The problem is I have 15k Client
s, so saving takes some seconds. How do I pass the Client list I get from Retrofit
to a background thread
if I can't pass RealmObject
between threads?
This is the code I have right now, it blocks the UI for several seconds when I perform the save.
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());
}
Personally I would try to keep my service and persistence layers decoupled. Parse the network response to a Client class implemented as a simple POJO, and use RealmObjects only when dealing with the database (you would need some kind of mapping utility between the two 'client' entities).
If you really want to use Retrofit responses as RealmObjects you are probably going to need to drop the 'Callback' format in your API interface and implement your own threading solution so both the Retrofit and the Realm operations are performed in the same thread.
Basically, set it up so that you can execute something like this:
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
}
}
in a background thread.