I have to download some data as soon as user logs in to the app. I have put -the network calls to download this data and -the database transactions to write it to sqlite
in an intent service. The data is huge so, saving it to sqlite is taking time. But I'm wondering why the intent service is blocking the UI. I can't navigate through the application. If I click on any button nothing happens. If I click again, app just freezes and eventually causes ANR.
I was using Service earlier. As service runs on main thread, I'm using IntentService. I had concurrent AsyncTasks for downloading each set of data. Now I got rid of those AsyncTasks and handling all the network calls in onHandleIntent method. I'm testing on Android device of version 5.1.1(lollipop).
public class MastersSyncService extends IntentService {
private static final String TAG = "MastersSyncService";
private static final int CUSTOMERS_PAGE_LENGTH = 5000;
private Context mContext;
private DataSource dataSource;
private boolean isReset;
private ProgressDialog pDialog;
private int numOfCustReceived, pageNumber, customersVersion;
private AlertDialog alertDialog;
public MastersSyncService() {
super(TAG);
}
@Override
protected void onHandleIntent(Intent intent) {
mContext = MastersSyncService.this;
dataSource = new DataSource(mContext);
if (intent.getExtras() != null) {
isReset = intent.getBooleanExtra("isReset", false);
}
customersVersion = dataSource.customers.getVersion();
if (customersVersion == 0) {
dataSource.customers.truncateTable();
}
downloadPackingDataMasters();
downloadCommoditiesMasters(); //makes a network call and writes some simple data to sqlite
downloadPaymentTypesMasters(); //makes a network call and writes some simple data to sqlite
downloadReasonsMasters(); //makes a network call and writes some simple data to sqlite
downloadMeasurementTypesMasters(); //makes a network call and writes some simple data to sqlite
downloadDocketsMasters(); //makes a network call and writes some simple data to sqlite
downloadContractsMasters(); //makes a network call and writes some simple data to sqlite
downloadBookingModesMasters(); //makes a network call and writes some simple data to sqlite
downloadPincodeMasters(); //makes a network call and writes some simple data to sqlite
downloadCustomersMasters(); //this method has a recursive network call with pagination. Takes a lot of time
}
public void downloadCustomersMasters() {
try {
Globals.lastErrMsg = "";
String url = VXUtils.getCustomersUrl(customersVersion, pageNumber);
Utils.logD("Log 1");
InputStream inputStream = HttpRequest.getInputStreamFromUrlRaw(url, mContext);
if (inputStream != null) {
pageNumber++;
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
dataSource.beginTransaction();
String line = null;
while ((line = reader.readLine()) != null) {
if (Utils.isValidString(line)) {
numOfCustReceived++;
Utils.logD("line from InputStream: " + line);
parseCustomer(line);
}
}
dataSource.endTransaction();
} else {
numOfCustReceived = 0;
Utils.logD(TAG + " InputStream is null");
}
} catch (IOException ioe) {
ioe.printStackTrace();
System.out.println("Exception while reading input " + ioe);
} catch (Exception e) {
e.printStackTrace();
if (!Utils.isValidString(Globals.lastErrMsg))
Globals.lastErrMsg = e.toString();
if (Globals.lastErrMsg.equalsIgnoreCase("null"))
Globals.lastErrMsg = getString(R.string.server_not_reachable);
}
if (numOfCustReceived >= CUSTOMERS_PAGE_LENGTH) {
downloadCustomersMasters();
} else {
if (!Utils.isValidString(Globals.lastErrMsg) && pDialog != null && pDialog.isShowing()) {
Utils.updateTimeStamp(mContext, Constants.CUSTOMERS_DATE_PREF);
}
}
}
public void downloadPackingDataMasters() {
try {
Globals.lastErrMsg = "";
int version = dataSource.packingData.getVersion();
String url = VXUtils.getPackingDataUrl(version); //, imei, versionCode + ""
Utils.logD("Log 1");
PackingDataResponse response = (PackingDataResponse) HttpRequest
.getInputStreamFromUrl(url, PackingDataResponse.class,
mContext);
if (response != null) {
Utils.logD("Log 4");
Utils.logD(response.toString());
if (response.isStatus()) {
List<PackingDataModel> data = response.getData();
if (Utils.isValidArrayList((ArrayList<?>) data)) {
if (isReset)
dataSource.packingData.truncateTable();
int val = dataSource.packingData.savePackingData(data, version);
}
} else {
Globals.lastErrMsg = response.getMessage();
}
}
} catch (Exception e) {
if (!Utils.isValidString(Globals.lastErrMsg))
Globals.lastErrMsg = e.toString();
if (Globals.lastErrMsg.equalsIgnoreCase("null"))
Globals.lastErrMsg = getString(R.string.server_not_reachable);
}
if (!Utils.isValidString(Globals.lastErrMsg)) {
Utils.updateTimeStamp(mContext, Constants.PACKING_DATE_PREF);
}
}
private final char DEFAULT_QUOTE_CHARACTER = '"';
private final char DEFAULT_SEPARATOR_CHARACTER = ',';
private void parseCustomer(String line) {
char quotechar = DEFAULT_QUOTE_CHARACTER;
char separator = DEFAULT_SEPARATOR_CHARACTER;
if (line == null) {
return;
}
List<String> tokensOnThisLine = new ArrayList<String>();
StringBuffer sb = new StringBuffer();
boolean inQuotes = false;
for (int i = 0; i < line.length(); i++) {
char c = line.charAt(i);
if (c == quotechar) {
if (inQuotes && line.length() > (i + 1)
&& line.charAt(i + 1) == quotechar) {
sb.append(line.charAt(i + 1));
i++;
} else {
inQuotes = !inQuotes;
if (i > 2 && line.charAt(i - 1) != separator
&& line.length() > (i + 1)
&& line.charAt(i + 1) != separator) {
sb.append(c);
}
}
} else if (c == separator && !inQuotes) {
if (Utils.isValidString(sb.toString())) {
String str = sb.toString().trim();
tokensOnThisLine.add(str);
} else {
tokensOnThisLine.add(sb.toString());
}
sb = new StringBuffer();
} else {
sb.append(c);
}
}
if (Utils.isValidString(sb.toString())) {
String str = sb.toString().trim();
tokensOnThisLine.add(str);
} else {
tokensOnThisLine.add(sb.toString());
}
int customerId = Integer.parseInt(tokensOnThisLine.get(0));
String custName = tokensOnThisLine.get(2);
Utils.logD("CUST: " + customerId + " " + custName);
dataSource.customers.saveCustomerDirect(
customerId,
tokensOnThisLine.get(1),
custName,
tokensOnThisLine.get(3),
tokensOnThisLine.get(4),
tokensOnThisLine.get(5),
tokensOnThisLine.get(6),
tokensOnThisLine.get(7),
Integer.parseInt(tokensOnThisLine.get(8)),
Integer.parseInt(tokensOnThisLine.get(9)),
Integer.parseInt(tokensOnThisLine.get(10)),
Integer.parseInt(tokensOnThisLine.get(11)),
Integer.parseInt(tokensOnThisLine.get(12)));
}
Downloading data is taking several minutes. I can't make the user wait for such long time. Please suggest how to make the UI interactive while the data is being downloaded in the background. Or please suggest ways to save huge number of records to sqlite quickly