0

執行的AsyncTask我已閱讀,在Activity執行AsyncTask的缺點是任務不更改配置好應付,因爲AsyncTask的生命週期上沒有Activity生命週期的束縛。因此,如果任務應更新活動的UI,但同時Activity由於配置更改而被破壞,AsyncTask不知道新創建的Activity的任何內容,因此無法更新它。這也可能導致內存泄漏。在無頭的片段

解決方法建議它使用無頭FragmentFragment不帶用戶界面),只是爲了執行AsyncTask,因爲它可以在配置更改後保留。儘管如此,我不理解它是如何可行的,因爲無論如何Activity及其觀點已被破壞。例如:

public MyFragment extends Fragment { 
     private SomeAsync myAsync = new SomeAsync(); 
     private WeakReference<View> someActivityView; 

     @Override 
     public void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      setRetainInstance(true); 
     } 

     public void setActivityView(View View) { 
      someActivityView = new WeakReference<View>(view); 
     } 

     ... 

     class SomeAsync extends AsyncTask<Void, Integer, Object> { 

     protected Object doInBackground(Void... args) { 
     ... 
     } 

     protected void onPostExecute(Object result) { 
      doUpdate(someActivityView, result); 
     } 

     } 
     } 

someActivityViewView屬於Activity和它被設置爲Fragment進行更新。 我認爲someActivityView不會保留在配置更改的情況下,而Activity再次創建,因此在這種情況下使用無頭Fragment有什麼好處?

+0

您不應該直接更新活動視圖。創建一個回調並在活動中實現它。現在在片段中使用getActivity()並將其轉換爲回調並使用它。 –

回答

2

是的,你讀到的有關AsyncTask的內容是真實的,yes viewLess片段是一種解決方法。

對片段做某事的一般想法是它可以訪問當前活動活動的任何活動。這樣,而不是使用public void setActivityView(View View) {存儲實際視圖,您應該只存儲此視圖的id,並在需要時在活動中找到它。

我將複製您的代碼並在其上更改一些內容以顯示結果。但還有其他的方式。最後我會簡要地談談他們。

public MyFragment extends Fragment { 
     private SomeAsync myAsync = new SomeAsync(); 
     private int viewId = -1; 

     @Override 
     public void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      setRetainInstance(true); 

      // restore the view id 
      if(savedInstanceState != null && savedInstanceState.containsKey("myViewId")){ 
        viewId = savedInstanceState.getInt("myViewId"); 
      } 
     } 

     @Override 
     public void onSaveInstanceState (Bundle outState) { 
      super.onSaveInstanceState(outState); 
      // save the view ID 
      if(viewId > 0) { 
       outState.putInt("myViewId", viewId); 
      } 
     } 

     public void setActivityView(View View) { 
      viewId = view.getId(); 
     } 

     ... 

     class SomeAsync extends AsyncTask<Void, Integer, Object> { 

     protected Object doInBackground(Void... args) { 
     ... 
     } 

     protected void onPostExecute(Object result) { 
      Activity activity = getActivity(); 
      if(viewId > 0 && activity != null) { 
       View view = activity.findViewById(viewId); 
       doUpdate(view, result); 
      } 
     } 

     } 
     } 

是的,這是需要保存ID,因爲是你的活動可能被殺死其他原因(如切換到後臺和系統運行內存不足);

備選方案:

  1. 放視圖ID直接進入片段setArguments(bundle)
  2. 使活動實現與接收您的AsyncTask的方法的接口。然後onPostExecute您撥打getActivity,投射到此界面並直接將結果傳遞給活動。
  3. (這是我最喜歡的選擇,因爲它是最乾淨的):不要使用AsyncTask,也不要將處理結果與UI組件捆綁在一起。用數據,處理和UI分離創建適當的結構。 UI元素只應根據對數據元素的訂閱進行更新。有幾種模式可以幫助分離責任人。 MVP,MVC,MVVM等選一個。
+0

如果我使用AsyncTask,兩個第一選項之一是必不可少的。我不認爲第三個選項是我的問題的整體解決方案。即使視圖是由separete類管理的,也應該執行回調來通知它。 – arjacsoh