У меня есть активность с 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 для хранения и управления состоянием между перезапусками активности.
Проблема в том, что при изменении конфигурации (например, ориентация переключателя):
- Разрушенный открытый фрагмент
- Разрушенная активность
- Перезапущенная активность
- В методе onCreate при вызове super.onCreate (saveInstanceState) менеджер фрагментов воссоздает фрагмент (уничтожается на шаге 1) с помощью конструктор по умолчанию (без параметров).
- Мой код в методе onCreate восстанавливает уничтоженный фрагмент. Итак, фрагмент, воссозданный менеджером фрагментов, уничтожен и заменен на мой фрагмент, созданный на этом шаге.
Как избежать этого поведения? Мне не нужен фрагмент, восстановленный менеджер фрагментов. Также мне не нужен конструктор по умолчанию для моих фрагментов (у меня есть какой-то пользовательский ViewModel, внедренный для фрагментации через конструктор из размещенной активности)
Поместить null в super.onCreate ()? Я думаю, что это не очень хорошее решение ...
PS Я знаю о ViewPager и ViewPager2 для управления вкладками TabLayout. ViewPager устарел. А с ViewPager2 у меня странная ошибка: первая вкладка (с индексом 0) работает нормально, но во второй вкладке я не могу сосредоточиться на каком-либо вводе (нажмите на ввод и фокус сразу потерян, не знаю почему).