EDIT: tl;dr How do you insert into db using content resolver and simpleCursorAdapter without a listfragment hanging?
I have an AsyncTask that I am using to download JSON data. In onPostExecute() of that task I call handleNewMessageReponse() to update my Sqlite database with the results.
The code for handleNewMessageResponse()
private void handleNewMessagesResponse() {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
//Step 1. Ensure we got something back.
if (mMessagesResponse.getMessages().length > 0){
//Step 2. Delete all Message DB rows.
getActivity().getContentResolver().delete(EntegraContentProvider.CONTENT_URI_MESSAGES, null, null);
//Step 3. Populate DB with new info.
//Hangs UI here.
for (int i = 0; i < mMessagesResponse.getMessages().length; i++) {
Messages messages = mMessagesResponse.getMessages()[i];
ContentValues values = new ContentValues();
values.put("id", messages.getId());
values.put("parent", messages.getParent());
values.put("type", messages.getType());
values.put("user", messages.getUser());
values.put("subject", messages.getSubject());
values.put("body", messages.getBody());
values.put("datetime", messages.getDatetime());
values.put("status", messages.getStatus());
values.put("touched", messages.getTouched());
//Perform the Insert.
getActivity().getContentResolver().insert(
EntegraContentProvider.CONTENT_URI_MESSAGES, values);
mWasDataLoaded = true;
}
}
mDataListener.onDataFetchComplete();
}
});
}
This is all contained in a ListFragment which implements LoaderManager.LoaderCallbacks
The onCreate of this fragment looks like this:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] uiBindFrom = { "user", "subject" };
int[] uiBindTo = { R.id.messageUser , R.id.messageTitle };
getLoaderManager().initLoader(MESSAGES_LIST_LOADER, null, this);
adapter = new SimpleCursorAdapter(
getActivity(), R.layout.messages_list_item,
null, uiBindFrom, uiBindTo,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
setListAdapter(adapter);
}
Everything works great with one exception the below section of the code takes up to 10 seconds to execute and hangs the UI/List during the 10 seconds.
this section is when UI hangs:
//Step 3. Populate DB with new info.
for (int i = 0; i < mMessagesResponse.getMessages().length; i++) {
Messages messages = mMessagesResponse.getMessages()[i];
ContentValues values = new ContentValues();
values.put("id", messages.getId());
values.put("parent", messages.getParent());
values.put("type", messages.getType());
values.put("user", messages.getUser());
values.put("subject", messages.getSubject());
values.put("body", messages.getBody());
values.put("datetime", messages.getDatetime());
values.put("status", messages.getStatus());
values.put("touched", messages.getTouched());
//Perform the Insert.
getActivity().getContentResolver().insert(
EntegraContentProvider.CONTENT_URI_MESSAGES, values);
Can someone plese point me in the right direction and tell me what the standard approach to this seemingly common task is? This should be pretty simple but am having a hard time finding examples that fit my use case.
Thanks.
Here is my final code. Much more fluid:
private class EventsFetcher extends AsyncTask<String, Void, EventsResponse> {
private static final String TAG = "EventsFetcher";
@Override
protected EventsResponse doInBackground(String... params) {
EventsResponse returnResponse = null;
try {
//Create an HTTP client
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(mEventsBaseUrl);
//Perform the request and check the status code
HttpResponse response = client.execute(post);
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
try {
//Read the server response and attempt to parse it as JSON
Reader reader = new InputStreamReader(content);
Gson gson = new Gson();
returnResponse= gson.fromJson(reader, EventsResponse.class);
content.close();
} catch (Exception ex) {
Log.e(TAG, "Failed to parse JSON due to: " + ex);
failedGettingEvents();
}
} else {
Log.e(TAG, "Server responded with status code: " + statusLine.getStatusCode());
failedGettingEvents();
}
} catch(Exception ex) {
Log.e(TAG, "Failed to send HTTP POST request due to: " + ex);
failedGettingEvents();
}
return returnResponse;
}
@Override
protected void onPostExecute(EventsResponse resultResponse) {
EventsResultsHandler resultsHandler = new EventsResultsHandler();
resultsHandler.execute(resultResponse);
}
}
private class EventsResultsHandler extends AsyncTask<EventsResponse, Void, String> {
private static final String TAG = "EventsResultsHandler";
@Override
protected String doInBackground(EventsResponse... params) {
try {
EventsResponse evResponse = params[0];
//Step 1. Ensure we got something back.
if (evResponse.getEvents().length > 0){
//Step 2. Populate Array with new info.
List<ContentValues> jsonResults = new ArrayList<ContentValues>();
for (int i = 0; i < evResponse.getEvents().length; i++) {
Events events = evResponse.getEvents()[i];
ContentValues values = new ContentValues();
values.put("start_date", events.getStart_date());
values.put("end_date", events.getEnd_date());
values.put("name", events.getName().replace("'","''"));
values.put("location", events.getLocation().replace("'","''"));
values.put("summary", events.getSummary().replace("'","''"));
values.put("lat", events.getLat());
values.put("lng", events.getLng());
values.put("is_active", events.getIs_active());
values.put("hide_calendar_button", events.getHide_calendar_button());
values.put("hide_map", events.getHide_map());
jsonResults.add(values);
}
//Step 3. Delete all data in table.
getActivity().getContentResolver().delete(EntegraContentProvider.CONTENT_URI_EVENTS, null, null);
//Step 4. Insert new data via via Bulk insert.
getActivity().getContentResolver().bulkInsert(EntegraContentProvider.CONTENT_URI_EVENTS, jsonResults.toArray(new ContentValues[jsonResults.size()]));
mWasDataLoaded = true;
}
} catch(Exception ex) {
Log.e(TAG, "Failed to update results due to: " + ex);
failedGettingEvents();
}
return null;
}
@Override
protected void onPostExecute(String result) {
mDataListener.onDataFetchComplete();
}
}