Как избежать воссоздания фрагмента FragmentManager? - PullRequest
0 голосов
/ 02 апреля 2020

У меня есть активность с TabLayout и двумя фрагментами, представляющими содержимое вкладки. Текущее состояние открытой вкладки я управляю вручную в методе OnCreate своей деятельности:

import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;

import com.google.android.material.tabs.TabLayout;

public class LoginActivity extends AppCompatActivity {

    private TabLayout tabLayout;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        tabLayout = findViewById(R.id.tabLayout);

        //initialize or restore opened tab, after activity first started or recreated
        int tabIndex = savedInstanceState == null ? 0 : savedInstanceState.getInt("tabIndex");
        Fragment f;
        switch (tabIndex) {
            case 0:
                f = new SignInFragment();
                break;
            case 1:
                f = new SignUpFragment();
                break;
            default:
                throw new UnsupportedOperationException();
        }
        //sync tab indicator
        tabLayout.selectTab(tabLayout.getTabAt(tabIndex));
        //set opened fragment
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.tabContent, f)
                .commit();

        //add listener to handle tab switching
        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                Fragment tabFragment;
                switch (tab.getPosition()) {
                    case 0:
                        tabFragment = new SignInFragment();
                        break;
                    case 1:
                        tabFragment = new SignUpFragment();
                        break;
                    default:
                        throw new UnsupportedOperationException();
                }
                getSupportFragmentManager().beginTransaction()
                        .setCustomAnimations(com.google.android.material.R.anim.abc_grow_fade_in_from_bottom, com.google.android.material.R.anim.abc_shrink_fade_out_from_bottom)
                        .replace(R.id.tabContent, tabFragment)
                        .commit();
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });
    }

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("tabIndex", tabLayout.getTabAt(tabLayout.getSelectedTabPosition()).getPosition());
    }
}

Это просто пример. Мой реальный код написан на C# и имеет некоторые другие логики c для хранения и управления состоянием между перезапусками активности.

Проблема в том, что при изменении конфигурации (например, ориентация переключателя):

  1. Разрушенный открытый фрагмент
  2. Разрушенная активность
  3. Перезапущенная активность
  4. В методе onCreate при вызове super.onCreate (saveInstanceState) менеджер фрагментов воссоздает фрагмент (уничтожается на шаге 1) с помощью конструктор по умолчанию (без параметров).
  5. Мой код в методе onCreate восстанавливает уничтоженный фрагмент. Итак, фрагмент, воссозданный менеджером фрагментов, уничтожен и заменен на мой фрагмент, созданный на этом шаге.

Как избежать этого поведения? Мне не нужен фрагмент, восстановленный менеджер фрагментов. Также мне не нужен конструктор по умолчанию для моих фрагментов (у меня есть какой-то пользовательский ViewModel, внедренный для фрагментации через конструктор из размещенной активности)

Поместить null в super.onCreate ()? Я думаю, что это не очень хорошее решение ...

PS Я знаю о ViewPager и ViewPager2 для управления вкладками TabLayout. ViewPager устарел. А с ViewPager2 у меня странная ошибка: первая вкладка (с индексом 0) работает нормально, но во второй вкладке я не могу сосредоточиться на каком-либо вводе (нажмите на ввод и фокус сразу потерян, не знаю почему).

1 Ответ

0 голосов
/ 02 апреля 2020

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

private Fragment signInFragment = new SignInFragment();
private Fragment signUpFragment = new SignUpFragment();
int tabIndex = savedInstanceState == null ? 0 : 
savedInstanceState.getInt("tabIndex");
    Fragment f;
    switch (tabIndex) {
        case 0:
            f = signInFragment
            break;
        case 1:
            f = signUpFragment
            break;
        default:
            throw new UnsupportedOperationException();
    }
...