【发布时间】:2014-02-10 14:54:26
【问题描述】:
编辑:tl;dr 如何使用内容解析器和 simpleCursorAdapter 插入 db 而不挂起 listfragment?
我有一个用于下载 JSON 数据的 AsyncTask。在该任务的 onPostExecute() 中,我调用 handleNewMessageReponse() 以使用结果更新我的 Sqlite 数据库。
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();
}
});
}
这都包含在一个实现 LoaderManager.LoaderCallbacks 的 ListFragment 中
此片段的 onCreate 如下所示:
@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);
}
一切都很好,除了一个例外,下面的代码部分最多需要 10 秒才能执行并在 10 秒内挂起 UI/List。
此部分是 UI 挂起的时间:
//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);
有人能指出我正确的方向并告诉我这个看似常见的任务的标准方法是什么吗?这应该很简单,但很难找到适合我用例的示例。
谢谢。
这是我的最终代码。更加流畅:
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();
}
}
【问题讨论】:
-
如果 ui 挂起,你应该在后台线程而不是 ui one 中更新你的数据库
-
pskink,这不是我在上面的代码中所做的吗? getActivity().runOnUiThread(new Runnable() { @Override public void run() {
-
对 runOnUiThread 的调用会安排一个 runnable 在 UI 线程上执行(该方法确实如其名称所暗示的那样......)。您需要在后台线程或另一个 AsyncTask 上启动 handleNewMessagesResponse 代码。
-
NigelK,对不起,我忘了说我试过了。当我按照您的建议进行操作时,列表不再完全挂起,但滚动时非常生涩。然后它消失,然后在最后闪回。
标签: android sqlite user-interface bulkinsert android-contentresolver