2012-02-17 92 views
0

問題:活動A是一個ListView,其中包含ListAdapter,並且單擊適配器的任何項目都會導致活動B.活動B有一個按鈕,用於從Web中獲取一個或多個新項目(使用AsyncTask)和將其添加到按下時由活動A顯示的列表中。來自B的操作不會被ProgressDialog阻止,因此用戶可以在B開始的AsyncTask完成提取數據之前移回到A.如何從其他活動更新活動的適配器?

所以我需要從B.

我有在ListView由A.當在B點的按鈕被按下時顯示靜態數據的C類更新的適配器的方式,增加該值C.這個類也有來自A的適配器作爲靜態字段,但我認爲這會泄漏來自Context的內存,這很糟糕。我確定這的第一個想法是去除C和每次靜態適配器A onResume()(如果適配器上的數據是從我都位於C不同),我從C的數據加載又進了適配器和notifyDatasetChanged()。那麼,大多數情況下它都能正常工作,但是如果用戶在B從Web獲取數據之前從B返回A,那麼適配器不會更新,因爲onResume()在獲取數據之前就已經出現了。

問:有沒有的B更新的適配器的更好的辦法?

回答

0

不要保存到適配器靜態引用。它確實會泄漏記憶並且表現不好。

看來我誤解了第一次。下面是一個更新的答案:

首先解決

最漂亮的解決方案是實現對數據存儲的內容提供商和查詢的內容提供商在A與B兩者使用的ContentProvider更新B中的數據。插入() 和讀取使用contentProvider.query(),如果它是由數據庫或MatrixCursor支持,如果你只是將它保存在內存中的內容提供商返回例如SQLiteCursor數據。

的基本步驟(無CursorLoader):

  1. 在A的的onCreate你自己註冊爲在那裏URI是使用一些方案設置的URI使用ContentResolver.registerContentObserver(uri, true, this)一個contentobserver。
  2. 在onCreate of A中,您可以通過使用ContentResolver.query(uri, projection, selection, selectionArgs, sortOrder)查詢contentprovider來獲取數據,其中projection,selection,selectionArgs和sortOrder可以是適合您的contentprovider(可能爲null)的內容。 Uri引用您想要查詢的數據並且是您的選擇。
  3. 當數據在裝載了B打電話ContentResolver.insert()。在您的ContentProvider的insert你打電話ContentResolver.notifyChange (Uri uri, null, null)其中URI是URI您在步驟1
  4. 用於實現一個的onChange(布爾selfChange),並重新查詢內容提供商時,它被調用。

請注意,如果您使用CursorLoaders,則根本不需要調用registerContentObserver! 它將在加載器中接收新的遊標,因爲它在通知更改時具有自動重新查詢。

第二溶液 一個不太漂亮的解決方案是實現處理該數據的單一對象。 喜歡的東西:

  1. 實現類

    public class DataHolder { 
        private static DataHolder sDataHolder; 
    
        private String data = ""; // Data represented by string. 
        public DataHolder getInstance() { 
         if (sDataHolder == null) { 
          sDataHolder = new DataHolder() 
         } 
         return sDataHolder; 
        } 
    
        private DataHolder() {} // Hidden constructor 
    
        public void setData(final String data) { 
         mData = data; 
    
         for (DataListener listener: mDataListeners) { 
          listener.onDataChanged(mData); 
         } 
        } 
    
        public void registerListener(DataListener listener) { 
         mDataListeners.add(listener); 
        } 
    
        public String unregisterListener(DataListener listener) { 
         mDataListeners.remove(listener); 
        } 
    
        public String getData() { 
         return mData; 
        } 
    
        public static interface DataListener { 
         public void onDataChanged(String data); 
        } 
    } 
    
  2. 讓一個工具的DataListener
  3. 閱讀和的DataListener的onStart()更新數據,以確保如果變化的時候做到了它被設置B還活着使用​​。
  4. 使用DataHolder.getInstance().registerListener(this);在A的onCreate/onStart中註冊偵聽器讓偵聽器更新數據。
  5. 在A的的onDestroy註銷監聽器/的onStop使用DataHolder.getInstance().unregisterListener(this)
  6. 設定數據,並使用DataHolder.getInstance().setData(data)

另外請注意,你可以讓第二個解決方案完全線程安全的,通過改變void registerListener()synchronized String registerListenerAndGetValue()中頻信號B中任意監聽器你也使setValue同步。

基於一種誤解老答案

我以前的答案一般結果的處理並沒有完全回答這個問題,但它是:

如果你想將數據發送回一個活性的你應做到以下幾點:

使用乙完成後
  1. 始終以startActivityForResult (Intent intent, int requestCode)
  2. 將結果入門C
  3. 處理的結果,當你回來一個通過實施onActivityResult (int requestCode, int resultCode, Intent data)

作爲補充,你可以添加,所以你只有這樣它才savedInstanceState == null在例如取A中的第一次數據的onCreate() 。

+0

用戶可以按下BACK按鈕(並在'onActivityResult()'中獲得'RESULT_CANCEL'作爲結果代碼),而數據仍然在activity B中獲取。他將如何繼續進行這種情況?確切地說, – Luksprog 2012-02-17 19:19:02

+0

。 B中的數據將在AsyncTask中獲取,並且在數據結束時將數據設置爲C.如果用戶按下B中的BACk,則活動將結束,但數據仍將在AsyncTask中獲取。 – hgm 2012-02-17 19:23:31

+0

我誤解了這個問題。對不起。我在編輯的答案中添加了兩個解決方案。 – 2012-02-17 19:49:37

0

嘗試調用mListView.invalidate();

* * java-doc的

無效整個視圖。如果視圖可見,onDraw(android.graphics.Canvas)將在未來的某個時間點被調用。這必須從UI線程調用。要從非UI線程調用,請調用postInvalidate()