Фрагмент, не получающий обновления LiveData после удаления + добавления - PullRequest
0 голосов
/ 03 ноября 2018

Я сейчас играю вокруг, чтобы узнать жизненный цикл fragment в отношении ViewModel и LiveData.

У меня есть 2 fragments, fragmentA и fragmentB. Я добавляю Observer в onCreate метод каждого fragment.

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    sharedViewModel = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
    sharedViewModel.getText().observe(this, new Observer<CharSequence>() {
        @Override
        public void onChanged(CharSequence charSequence) {
            editText.setText(charSequence);
        }
    });
}

Каждый fragment имеет кнопку, которая меняет LiveData в общем ViewModel

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    [...]

    buttonOk.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            sharedViewModel.setText(editText.getText());
        }
    });

    [...]
}

SharedViewModel

public class SharedViewModel extends ViewModel {
    private MutableLiveData<CharSequence> text = new MutableLiveData<>();

    public void setText(CharSequence input) {
        text.setValue(input);
    }

    public LiveData<CharSequence> getText() {
    return text;
    }
}

Когда я нажимаю кнопку, я заменяю fragment на другую.

public class MainActivity extends AppCompatActivity {
    Fragment fragmentA = new FragmentA();
    Fragment fragmentB = new FragmentB();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.container_a, fragmentA)
                    .commit();
        }
    }

    public void switchToA(View v) {
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, fragmentA)
                .commit();
    }

    public void switchToB(View v) {
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, fragmentB)
                .commit();
    }
}

Replace приводит к полному уничтожению fragment и выполнению его метода onCreate при следующем добавлении. Я могу подтвердить, что onCreate вызывается для каждого fragment, помещенного на экран, и добавляется Observer. Но как только я заменил fragment и снова добавил его, он полностью прекращает получать какие-либо обновления в onChanged. Даже те, которые он отправил сам. onChanged просто больше не срабатывает. Я не понимаю почему.

Edit:

Я обнаружил, что проверка followig if в классе LiveData возвращает 2-й раз Я пытаюсь добавить Observer (после замены fragment на первый) :

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }

Следовательно, Observer больше не добавляется. Почему getCurrentState() возвращает DESTROYED, когда я пытаюсь повторно добавить fragment?

Вкратце: Observer удаляется при удалении fragment, но не добавляет еще Observer при следующем добавлении фрагмента.

1 Ответ

0 голосов
/ 03 ноября 2018

Согласно документации Lifecycle.State.DESTROYED :

После этого события этот жизненный цикл больше не будет отправлять события.

Т.е., DESTROYED - это состояние терминала, и как только оно будет уничтожено, этот жизненный цикл будет всегда разрушен.

Это означает, что есть два правильных способа сделать то, что вы хотите:

  1. Создайте новый экземпляр Fragment каждый раз, когда вы вызываете switchToA или switchToB. Поскольку при удалении фрагмента все состояние разрушается, вы не получаете ничего, повторно используя экземпляры фрагмента.

  2. Не используйте replace, а вместо этого используйте attach() и detach() (т.е. прикрепите тот, который вы хотите отобразить, отсоедините тот, который вы хотите скрыть). Фрагменты сохраняют свое состояние при отсоединении (они не уничтожаются), поэтому при повторном присоединении он возвращается к возобновлению.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...