2015-01-27 2 views
1

В моем контексте проекта у меня есть кнопка b в фрагменте f(1) в действии a.«Невозможно выполнить это действие после onSaveInstanceState» при замене фрагмента

Фрагмент f(x) является экземпляром F, где содержание зависит от аргумента x

Мне нужно заменить текущий экземпляр f(1) экземпляром f(2) на b клик событие:

  • От деятельности a:

    private void setFragment(int x) { 
        Bundle args = new Bundle(); 
        args.putInt("x", x); 
        F f = new F(); 
        f.setArguments(args); 
        f.setListener(new F.Listener() { 
         public void onButtonClick(int x) { 
          setFragment(x); 
         } 
        }); 
        getSupportFragmentManager() 
         .beginTransaction() 
         .replace(ID, f) 
         .commit(); 
    } 
    
  • Из фрагмента f:

    b.setOnClickListener(new View.onClickListener() { 
        public void onClick(View view) { 
         listener.onButtonClick(x + 1); 
        } 
    }); 
    

Моей проблемы:

Исключения составляет бросить на b событии нажатия только при изменении состояния конфигурации происходит:

Ява. lang.IllegalStateException: не удается выполнить это действие после onSaveInstanceState

Какая у меня ошибка? Я прочитал много сообщений об этом исключение, но я не нашел любое решение


Edit: Я просто сделать тест без AsyncTask см код:

Попробуйте повернуть экран и нажать кнопку

public class MainActivity extends ActionBarActivity { 

    @Override 
    protected void onCreate(Bundle state) { 
     super.onCreate(state); 
     setContentView(R.layout.activity_main); 
     if (state == null) { 
      setFragment(1); 
     } 
    } 

    private void setFragment(int id) { 
     Bundle args = new Bundle(); 
     args.putInt("id", id); 
     MyFragment myFragment = new MyFragment(); 
     myFragment.setArguments(args); 
     myFragment.setListener(new MyFragment.Listener() { 
      @Override 
      public void onClick(int id) { 
       setFragment(id); 
      } 
     }); 
     getSupportFragmentManager() 
      .beginTransaction() 
      .replace(R.id.fragment, myFragment) 
      .commit(); 
    } 

    public static class MyFragment extends Fragment{ 

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

     @Override 
     public View onCreateView(LayoutInflater inflater, ViewGroup view, Bundle state) { 
      return new Button(getActivity()) { 
       { 
        setText(String.valueOf(getArguments().getInt("id"))); 
        setOnClickListener(new View.OnClickListener() { 
         @Override 
         public void onClick(View view) { 
          listener.onClick(getArguments().getInt("id") + 1); 
         } 
        }); 
       } 
      }; 
     } 

     private static interface Listener { 
      public void onClick(int id); 
     } 

     private Listener listener; 

     public void setListener(Listener listener) { 
      this.listener = listener; 
     } 

    } 

} 
+0

Вы пришли по этому адресу http://stackoverflow.com/questions/7575921/illegalstateexception-can-not-perform-this-action-after-onsaveinstancestate-h, ответ говорит, что у вас есть использовать 'transaction.commitAllowingStateLoss();' вместо 'transaction.commit();' – Yazan

+0

Спасибо, мне жаль, что я поменял свой пост, я сказал большой ***. Да, я пробовал, но он не работает – alex

+0

Я бы предложил изменить свой подход, чтобы заменить фрагмент с помощью кнопки, которая является частью активности, а не самого фрагмента. Вы можете попробовать разместить его под текущим фрагментом. – ata

ответ

1

Проблема заключается в том, как вы устанавливаете слушателя. Вы устанавливаете слушатель, затем вы поворачиваете устройство от пейзажа к портрету. Что происходит после поворота:

  1. Android создает новый экземпляр MainActivity.
  2. FragmentManager создайте новый экземпляр MyFragment внутренне и автоматически добавьте его к активности, как это было до изменения ориентации.
  3. Если вы нажмете на кнопку, вызывается слушатель. Однако слушатель является слушателем предыдущего действия (до ротации), который был уничтожен.

Таким образом, у вас не только утечка памяти (старая активность не может быть собрана мусором, поскольку она указана здесь), но вы также получите эту ошибку.

Как это сделать правильно: Ну, проблема не только setRetainInstanceState() Вы не поняли жизненный цикл Android Fragments правильно. Как упоминалось выше, Фрагменты контролируются FragmentManager (FragmentTransaction).Итак, да, каждый раз, когда вы поворачиваете свой экран, будет создан новый экземпляр фрагмента, но FragmentManager будет автоматически их прикреплять к вам (это немного странно, но так как работает фрагмент)

Я бы рекомендовал использовать EventBus. Фрагмент будет запускать событие onClick(), и действие получит это событие с момента его подписания. Я пересчитываю GreenDao EventBus. В противном случае вы можете взглянуть на official docs, но с моей точки зрения они не участвуют в хорошем решении, потому что ваш фрагмент и активность вряд ли связаны (а не модульными). Говорят, вы должны использовать onAttach(), как вы можете видеть в образце из документации: http://developer.android.com/guide/components/fragments.html#EventCallbacks

КПП. аналогичная проблема может возникнуть, если вы не используете аргументы фрагмента для «передачи» данных. Для получения дополнительной информации читайте этот блог: http://hannesdorfmann.com/android/fragmentargs/

+0

Я эффективно управляю некоторыми AsyncTasks, но я уверен, что они остановлены и выпущены. Я подозреваю, что FragmentManager пытается повторно использовать последний фрагмент, потому что он исходит из того же класса, что и новый. – alex

+0

Итак, вы уверены, что AsyncTask не обращается к компонентам представления фрагментов после замены фрагмента другим? Поскольку существует рекурсия, вы уверены, что Listener не выполняет некоторые действия после того, как событие щелчка инициировалось на старом фрагменте? – sockeqwe

+0

Уверен, пожалуйста, см. Мое обновление – alex

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