onCreate() вызывается дважды при изменении конфигурации во фрагменте с ViewPager
Общий контекст:
У меня есть MainActivity с MainFragment. MainFragment имеет ViewPager, и я использую FragmentStatePagerAdapter для отображения DetailFragments на основе содержимого SqliteDatabase. Содержимое этой базы данных отображается и управляется в LocationActivity. Когда я нажимаю на элемент в LocationActivity, я использую intent.putextra, чтобы прикрепить позицию элемента, а затем отображаю правильную позицию в ViewPager в MainFragment. Когда я добавляю элемент в LocationActivity, он сохраняет положение элемента в SharedPreferences, и я получаю правильную позицию в MainFragment, чтобы отобразить фрагмент только что добавленного элемента.
Проблема:
Это работает, но когда происходит изменение конфигурации, я теряю фактическую страницу, выбранную из ViewPager. Поэтому я сохраняю позицию с помощью onSaveInstanceState(), если она не равна нулю, я извлекаю ее в onCreateView() и в onViewCreated(). Я прохожу операторы if, чтобы получить позицию, требуемую для ViewPager.setCurrentItem() в зависимости от условия. Но тогда onCreate() вызывается во второй раз, onSaveInstanceState() становится нулевым, и я теряю страницу, которая была выбрана до изменения конфигурации. Вы знаете, почему это называется дважды? Что я могу сделать, чтобы предотвратить это? Спасибо за вашу помощь
Журнал
06-24 09:15:05.974 activityMain.MainFragment: onLoadFinished() onPageSelected() 2
06-24 09:15:08.276 activityMain.MainFragment: onSaveInstanceState() 2
06-24 09:15:08.320 activityMain.MainFragment: onCreate()
06-24 09:15:08.342 activityMain.MainFragment: onCreateView()
06-24 09:15:08.342 activityMain.MainFragment: onCreateView() savedInstanceState Position: 2
06-24 09:15:08.349 activityMain.MainFragment: onViewCreated() get position from mCurrentPositionState 2
06-24 09:15:08.349 activityMain.MainFragment: onActivityCreated()
06-24 09:15:08.394 activityMain.MainFragment: onCreate()
06-24 09:15:08.396 activityMain.MainFragment: onCreateView()
06-24 09:15:08.401 activityMain.MainFragment: onViewCreated()) get position from SharedPreferences 4
06-24 09:15:08.401 activityMain.MainFragment: onActivityCreated()
06-24 09:15:08.407 activityMain.MainFragment: onResume()
06-24 09:15:08.458 activityMain.MainFragment: restartCursorLoader
06-24 09:15:08.508 activityMain.MainFragment: onLoadFinished()
06-24 09:15:08.537 activityMain.MainFragment: onLoadFinished() setCurrentItem: 4
Минимальный, полный и проверяемый пример
MainFragment.java
public class MainFragment extends Fragment {
public MainFragment() {
// Required empty public constructor
}
private static final String TAG = MainFragment.class.getName();
private static final String PAGE_SELECTED = "state_instance";
private MainPagerAdapter mAdapter;
private ViewPager mViewPager;
private int mLocationPosition;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (savedInstanceState != null) {
mLocationPosition = savedInstanceState.getInt(PAGE_SELECTED);
Log.i(TAG, "onCreateView() savedInstanceState not null, position: " + mLocationPosition);
} else {
mLocationPosition = 0;
Log.i(TAG, "onCreateView() savedInstanceState null, position: " + mLocationPosition);
}
return inflater.inflate(R.layout.fragment_main, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mViewPager = (ViewPager) view.findViewById(R.id.view_pager);
mAdapter = new MainPagerAdapter(getActivity().getSupportFragmentManager());
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewPager.setAdapter(mAdapter);
mViewPager.setCurrentItem(mLocationPosition, false);
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mLocationPosition = position;
Log.i(TAG, "onActivityCreated() mLocationPosition value: " + mLocationPosition);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt(PAGE_SELECTED, mLocationPosition);
Log.i(TAG, "onSaveInstanceState() mLocationPosition value: " + mLocationPosition);
super.onSaveInstanceState(outState);
}
}
Основная деятельность
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, new MainFragment());
fragmentTransaction.commit();
}
}
MainDetailFragment
public class MainDetailFragment extends Fragment {
private static final String TAG = MainDetailFragment.class.getName();
private TextView mTextViewLocation;
protected static final String ARGUMENT_PAGE = "location_page";
protected static final String ARGUMENT_NAME = "location_name";
private String mLocation;
public MainDetailFragment() {
}
protected static MainDetailFragment newInstance(int page, String locationName) {
MainDetailFragment mainDetailFragment = new MainDetailFragment();
Bundle arguments = new Bundle();
arguments.putInt(MainDetailFragment.ARGUMENT_PAGE, page);
arguments.putString(MainDetailFragment.ARGUMENT_NAME, locationName);
mainDetailFragment.setArguments(arguments);
return mainDetailFragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments().containsKey(ARGUMENT_NAME)) {
mLocation = getArguments().getString(ARGUMENT_NAME);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_main_detail, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mTextViewLocation = (TextView) view.findViewById(R.id.tv_city_name);
mTextViewLocation.setText(mLocation);
}
}
MainPagerAdapter
public class MainPagerAdapter extends FragmentStatePagerAdapter {
private static final String TAG = MainPagerAdapter.class.getName();
private static int NUM_ITEMS = 3;
public MainPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
// Returns total number of pages
@Override
public int getCount() {
return NUM_ITEMS;
}
// Returns the fragment to display for that page
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return MainDetailFragment.newInstance(0, "Paris");
case 1:
return MainDetailFragment.newInstance(1, "London");
case 2:
return MainDetailFragment.newInstance(2, "New York");
default:
return null;
}
}
}
2 ответа
Вы должны убедиться, что вы не добавляете свой MainFragment второй раз после изменения конфигурации. Вы должны обновить свою активность, чтобы она выглядела так:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (savedInstanceState != null) {
return;
}
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, new MainFragment());
fragmentTransaction.commit();
}
Причина этого заключается в том, что Activity
сама уже имеет запись о MainFragment
добавляется и автоматически восстановит его после изменения конфигурации. Если вы снова выполните ту же транзакцию, сначала вы увидите восстановленную MainFragment
запуск, затем его собираются заменить на новый от нового Fragment
транзакция и новая, другая MainFragment
собирается пройти свой собственный процесс инициализации. Это приводит к тому, что кажется, что несколько звонков onCreate
за MainFragment
,
Вызовите это в onCreate() вашего MainFragment
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate()");
setRetainInstance(true);
}