Golan Shay
Golan Shay

Reputation: 1269

Storing content in Sqlite database through IntentService blocks the UI thread

I have lots of records which I pull from the webservice and I need to cache them locally. While doing this (over 1000 records) the UI thread is blocked and I get ANR warning. I thought that using IntentService for that will not block the UI. What as I doiung wrong?

Few code snippets:

public class ContentIntentService extends IntentService {

@Override
protected void onHandleIntent(Intent workIntent) {
    code = workIntent.getStringExtra("CODE");
    getContent(code);
}

private void getContent(final String code) {
    if (apiService == null) {
        Retrofit client = ApiClient.getClient();
        if (client != null)
            apiService = client.create(ApiInterface.class);
    }
    if (apiService == null) {
        MobileValetHelper.onConnectionFailed(mAppContext);
        return;
    }
    Call<SectionsResponse> call = apiService.getOutletContent(outletCode, outletCode, MobileValetHelper.getContentSessionToken(mAppContext));
    call.enqueue(new Callback<SectionsResponse>() {
        @Override
        public void onResponse(@NonNull Call<SectionsResponse> call, @NonNull Response<SectionsResponse> response) {
            if (response != null
                    && response.body() != null
                    && response.body().status != null
                    && response.body().status.equalsIgnoreCase("Success")
                    && response.body().sessionToken != null
                    && response.body().data != null
                    ) {
                        DataCacheHelper dataCacheHelper = new DataCacheHelper(ContentIntentService.this);
                        dataCacheHelper.insertItems(ContentIntentService.this, items);
                    }
            } else if (response != null
                    && response.errorBody() != null) {
                Log.e(TAG, "getContent response.errorBody(): " + response.errorBody().string());
            }
        }

        @Override
        public void onFailure(@NonNull Call<SectionsResponse> call, @NonNull Throwable t) {
            Log.e(TAG, "getContent onFailure: " + t.toString());
        }
    });
}

}

public class DataCacheHelper { private ContentIntentService mIntentService;

    public DataCacheHelper(ContentIntentService service) {
        mIntentService = service;
    }

    public void insertItems(final ArrayList<CategoryItem> items) {

        if (mIntentService != null && items != null) {
            try {
                ContentValues[] valueList = new ContentValues[items.size()];
                int i = 0;
                ContentValues values;
                for (final CategoryItem item : items) {
                    values = ItemsTable.getContentValues(item);
                    valueList[i++] = values;
                }
                context.getContentResolver().bulkInsert(provider.CONTENT_URI, valueList);
            } catch (Exception e) {
                e.printStackTrace();
            }
    }
}

}

Upvotes: 0

Views: 243

Answers (1)

CommonsWare
CommonsWare

Reputation: 1007359

First, never do something asynchronous from an IntentService. Once onHandleIntent() returns, the IntentService will be destroyed. In your case, the network I/O may still be going on, let alone the disk I/O.

Second, onResponse() is called on the main application thread, which is the source of your difficulty.

So, use execute() instead of enqueue() and do all of the work directly in the IntentService on the thread used for onHandleIntent().

Upvotes: 1

Related Questions