0

Я прочитал, что выполнение AsyncTask в Activity имеет тот недостаток, что задача не очень хорошо справляться с изменениями конфигурации, так как AsyncTask «s жизненный цикл не привязан на Activity жизненного цикла. Следовательно, если задача должна обновить пользовательский интерфейс Activity, но в то же время Activity был уничтожен из-за изменения конфигурации, AsyncTask ничего не знает о недавно созданном Activity, и поэтому у него нет никаких шансов его обновить. Это также может привести к утечке памяти.Выполнить AsyncTask в обезглавленный Фрагмент

Обходное решение предложило использовать безголовый Fragment (Fragment без интерфейса), просто для того, чтобы выполнить 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); 
     } 

     } 
     } 

someActivityView является View, который принадлежит к Activity и устанавливается в Fragment быть обновлен. Я думаю, что someActivityView не сохраняется в случае изменения конфигурации, а Activity создан снова, следовательно, в чем преимущество использования безголового Fragment в этом случае?

+0

Нельзя обновлять вид деятельности напрямую. Создайте обратный вызов и реализуйте его в действии. Теперь во фрагменте используйте getActivity() и отбросьте его для обратного вызова и используйте его. –

ответ

2

Да, то, что вы читаете о AsyncTask, истинно, да фрагмент 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); 
      } 
     } 

     } 
     } 

И да, это необходимо для сохранения идентификатора, потому что вы и другие причины ваша деятельность может быть убиты (например, идет в фоновом режиме и система работает из памяти);

Альтернативы:

  1. поместить вид ID непосредственно в фрагменте setArguments(bundle).
  2. Сделайте операцию реализацией интерфейса с методом, который принимает ваш AsyncTask. Затем onPostExecute вы вызываете getActivity, передаете этот интерфейс и передаете результат непосредственно в действие.
  3. (эта альтернатива является моей любимой, потому что она самая чистая): не используйте AsyncTask и не связывайте результат обработки с компонентами пользовательского интерфейса. Создайте правильную структуру с обработкой данных, обработкой и разделением пользовательского интерфейса. Элементы пользовательского интерфейса должны обновляться только на основе подписки на элементы данных. Существует несколько шаблонов, которые могут помочь в отделении ответственностей. MVP, MVC, MVVM и т. Д. Выберите один.
+0

Один из двух первых вариантов необходим, если я использую AsyncTask. Я не рассматриваю третий вариант как целое решение моего вопроса.Даже если представления управляются классом separete, для его уведомления необходимо выполнить обратный вызов. – arjacsoh

Смежные вопросы