0

編輯:TL;博士你怎麼插入使用內容解析器和simpleCursorAdapter沒有listfragment掛分貝?更新SQLite數據庫,並使用SimpleCursorAdapter使UI掛起

我有我使用它來下載JSON數據的的AsyncTask。在該任務的onPostExecute()中,我調用handleNewMessageReponse()來更新我的Sqlite數據庫和結果。

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

該片段的一個的onCreate爲ListFragment handleNewMessageResponse()的代碼看起來是這樣的:

@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 /列表。

這部分是當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(); 
    } 
} 
+0

如果UI掛起你應該更新你的數據庫在後臺線程沒有UI一個 – pskink

+0

pskink,這不正是我在上面的代碼我在做什麼? getActivity()。runOnUiThread(new Runnable(){ @Override public void run(){ – Doug

+1

對runOnUiThread的調用會調度一個可在UI線程上執行的runnable(該方法確實按照名稱的名稱執行......)。關閉在後臺線程或與其他的AsyncTask的handleNewMessagesResponse代碼。 – NigelK

回答

0

你不想運行在UI線程上的數據庫更新,因爲這將掛起UI,你所看到的。

但你更新的方法很可能導致你所描述的,因爲你使用的是光標適配器的問題。

你有效地清除數據庫和重新填充。如果遊標適配器在重寫所有行之前運行,您將在上面的第二條註釋中看到您正在討論的結果。

您有兩種選擇,第一種是加載到內存,然後快速交換列表適配器內部列表,方法是將指針交換到適配器中的列表數據,然後告訴列表適配器事情已更改。您必須在UI線程上進行交換,但由於它只是更新指向數據的指針,所以速度很快並且保持UI的響應。缺點是你必須在內存中有兩份數據才能進行交換。

第二,也許更難的是改變你與服務器同步,這樣你就不必清除一切並重裝所有的東西的方式,而是刪除,添加或修改單個記錄。我建議這條路線,但它可能會爲你更多的工作。

+0

我將編輯我的問題,並展示我終於實現了。這是好,但並不完美。隨着更新這一新的方式,列表和UI留液體,但你可以看到列表有時會在數據刷新期間閃爍,然後您可以看到一些記錄出現。不完美但可用。 – Doug