I have an application which perform many files download from a server, decode the file content (json format) and save it into realm database. It's an utility app for our customers and need to work offline, so it has to store a lot of information.
For doing that, I have a "sync" page where I perform all my web queries (20+).
My problem is that the full operation takes about 5 minutes, while I see many games downloading 500+Mb of datas and storing them nearly istantly.
I'm going to post the longest asyncTask I have which takes about 2 minutes to finish.
this is my object
public class Meter extends RealmObject {
public Meter(){}
@PrimaryKey
private String ID;
@Index
private String MARCA;
@Index
private String MATRICOLA;
private String NUMERO_CIFRE;
private String DIAMETRO;
private String SIGILLO;
private String NUMERO_LOTTO;
private String LUNGHEZZA;
private String COEFFICIENTE;
private String ID_ARTICOLO;
private Item articolo;
//...
}
I download it using this asyncTask:
public static class DownloadMetersAsyncTask extends AsyncTask<String, Integer, Boolean> {
private String newSha;
private GenericDbClassMethods genericDbClass;
//asyncTaskItem is just an object keeping my file info to identify it on server side like file name
private AsyncTaskSyncItem asyncTaskSyncItem;
//this is an interface that I use for handling the start-update-finish events
private IReturnFinishAndStatusToParent iReturnFinishAndStatusToParent;
private synchronized void setProgress(int progress) {
asyncTaskSyncItem.setProgress(progress);
iReturnFinishAndStatusToParent.onProgressUpdate(progress);
}
public DownloadMetersAsyncTask(Context ctx, AsyncTaskSyncItem asyncTaskSyncItem, IReturnFinishAndStatusToParent iReturnFinishAndStatusToParent) {
this.asyncTaskSyncItem = asyncTaskSyncItem;
this.iReturnFinishAndStatusToParent = iReturnFinishAndStatusToParent;
this.genericDbClass = new GenericDbClassMethods(ctx);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
setProgress(values[0]);
}
@Override
protected Boolean doInBackground(String... params) {
Realm realm = null;
final boolean[] ok = {true};
newSha = null;
try {
realm = Realm.getDefaultInstance();
publishProgress(5);
String url = "...";
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(600, TimeUnit.SECONDS)
.writeTimeout(600, TimeUnit.SECONDS)
.readTimeout(600, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build();
publishProgress(10);
Request request = new Request.Builder().url(url)
.addHeader("Content-Type", "application/json")
.addHeader("Connection", "close")
.build();
publishProgress(15);
Response response = client.newCall(request).execute();
publishProgress(20);
ResponseBody responseBody = response.body();
publishProgress(25);
try {
String myHeader = response.header("Content-Disposition");
if (myHeader != null) {
int position = myHeader.indexOf("filename=");
position += "filename=".length();
newSha = myHeader.substring(position);
}
} catch (Exception ex) {
newSha = null;
}
if (responseBody == null) {
return true;
}
final BufferedInputStream is = new BufferedInputStream(responseBody.byteStream());
publishProgress(45);
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
try {
Log.d("SYNC", "Meter - start delete");
realm.delete(Meter.class);
Log.d("SYNC", "Meter - end delete, start create");
realm.createAllFromJson(Meter.class, is);
publishProgress(100, 1);
genericDbClass.setSHA(realm, new Meter(), newSha); //another stuff, really fast, can be removed
} catch (Exception error) {
error.printStackTrace();
newSha = null;
ok[0] = false;
publishProgress(100, 0);
publishProgress(75);
}
}
});
is.close();
response.close();
} catch (IOException error) {
newSha = null;
publishProgress(100, 0);
} finally {
if (realm != null) {
realm.close();
}
}
return ok[0];
}
@SuppressWarnings("unchecked")
@Override
protected void onPostExecute(Boolean v) {
iReturnFinishAndStatusToParent.onFinish(v);
}
}
This code works, the problem is that even if the download takes some seconds, the database insert is taking 1-2 minutes and this is way to much.
I was wondering if there might be a better way for handling the operation like performing the insert async.
Thanks in advice
Edit, add timers (just checked)
- It takes less than 1 second to go from
onPreExecute
torealm.createAllFromJson(Meter.class, is)
(excluded). - Performing
realm.createAllFromJson(Meter.class, is)
takes 3 minutes 50 seconds