Мое приложение состоит из нескольких фрагментов. До сих пор у меня были ссылки на них, хранящиеся в пользовательском объекте приложения, но я начинаю думать, что я делаю что-то неправильно.Ссылка фрагмента на mActivity становится нулевой после изменения ориентации. Неэффективное обслуживание состояния фрагментов
Мои проблемы начались, когда я понял, что все ссылки моего фрагмента на mActivity становятся нулевыми после изменения ориентации. Поэтому, когда я вызываю getActivity() после изменения ориентации, генерируется исключение NullPointerException. Я проверил, что мой onAttach() вызывается перед тем, как сделать вызов getActivity(), но он все равно возвращает null.
Ниже приведена разделенная версия моего MainActivity, которая является единственным видом деятельности в моем приложении.
public class MainActivity extends BaseActivity implements OnItemClickListener,
OnBackStackChangedListener, OnSlidingMenuActionListener {
private ListView mSlidingMenuListView;
private SlidingMenu mSlidingMenu;
private boolean mMenuFragmentVisible;
private boolean mContentFragmentVisible;
private boolean mQuickAccessFragmentVisible;
private FragmentManager mManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
* Boolean variables indicating which of the 3 fragment slots are visible at a given time
*/
mMenuFragmentVisible = findViewById(R.id.menuFragment) != null;
mContentFragmentVisible = findViewById(R.id.contentFragment) != null;
mQuickAccessFragmentVisible = findViewById(R.id.quickAccessFragment) != null;
if(!savedInstanceState != null) {
if(!mMenuFragmentVisible && mContentFragmentVisible) {
setupSlidingMenu(true);
} else if(mMenuFragmentVisible && mContentFragmentVisible) {
setupSlidingMenu(false);
}
return;
}
mManager = getSupportFragmentManager();
mManager.addOnBackStackChangedListener(this);
final FragmentTransaction ft = mManager.beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
if (!mMenuFragmentVisible && mContentFragmentVisible) {
/*
* Only the content fragment is visible, will enable sliding menu
*/
setupSlidingMenu(true);
onToggle();
ft.replace(R.id.contentFragment, getCustomApplication().getSportsFragment(), SportsFragment.TAG);
} else if (mMenuFragmentVisible && mContentFragmentVisible) {
setupSlidingMenu(false);
/*
* Both menu and content fragments are visible
*/
ft.replace(R.id.menuFragment, getCustomApplication().getMenuFragment(), MenuFragment.TAG);
ft.replace(R.id.contentFragment, getCustomApplication().getSportsFragment(), SportsFragment.TAG);
}
if (mQuickAccessFragmentVisible) {
/*
* The quick access fragment is visible
*/
ft.replace(R.id.quickAccessFragment, getCustomApplication().getQuickAccessFragment());
}
ft.commit();
}
private void setupSlidingMenu(boolean enable) {
/*
* if enable is true, enable sliding menu, if false
* disable it
*/
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// launch the fragment that was clicked from the menu
}
@Override
public void onBackPressed() {
// Will let the user press the back button when
// the sliding menu is open to display the content.
if (mSlidingMenu != null && mSlidingMenu.isMenuShowing()) {
onShowContent();
} else {
super.onBackPressed();
}
}
@Override
public void onBackStackChanged() {
/*
* Change selected position when the back stack changes
*/
if(mSlidingMenuListView != null) {
mSlidingMenuListView.setItemChecked(getCustomApplication().getSelectedPosition(), true);
}
}
@Override
public void onToggle() {
if (mSlidingMenu != null) {
mSlidingMenu.toggle();
}
}
@Override
public void onShowContent() {
if (mSlidingMenu != null) {
mSlidingMenu.showContent();
}
}
}
Ниже приведена разделенная версия CustomApplication. Мои мысли, стоящие за этой реализацией, заключались в том, чтобы гарантировать только один экземпляр каждого фрагмента на протяжении всего жизненного цикла приложения.
public class CustomApplication extends Application {
private Fragment mSsportsFragment;
private Fragment mCarsFragment;
private Fragment mMusicFragment;
private Fragment mMoviesFragment;
public Fragment getSportsFragment() {
if(mSsportsFragment == null) {
mSsportsFragment = new SportsFragment();
}
return mSsportsFragment;
}
public Fragment getCarsFragment() {
if(mCarsFragment == null) {
mCarsFragment = new CarsFragment();
}
return mCarsFragment;
}
public Fragment getMusicFragment() {
if(mMusicFragment == null) {
mMusicFragment = new MusicFragment();
}
return mMusicFragment;
}
public Fragment getMoviesFragment() {
if(mMoviesFragment == null) {
mMoviesFragment = new MoviesFragment();
}
return mMoviesFragment;
}
}
Мне очень интересны советы о том, как наилучшим образом реализовать множественные фрагменты и как поддерживать их состояния. Для вашей информации мое приложение состоит из 15 + фрагментов. Я провел некоторое исследование, и кажется, что FragmentManager.findFragmentByTag() - хорошая ставка, но я не смог его успешно реализовать.
Мое выполнение, похоже, работает хорошо, за исключением того факта, что ссылки на токтивность становятся нулевыми после изменений ориентации, что позволяет мне поверить, что у меня могут быть проблемы с утечкой памяти.
Если вам нужно увидеть больше кода, пожалуйста, дайте мне знать. Я намеренно избегал использования кода фрагмента, так как я уверен, что проблемы связаны с моими реализациями Activity и Application, но я могу ошибаться.
Спасибо за ваше время.
Спасибо за ваш быстрый ответ! Я сделаю необходимые изменения в соответствии :) Только один быстрый вопрос: когда мое приложение будет уничтожено Android для ресурсов, как я могу гарантировать, что когда пользователь запустит мое приложение, последний фрагмент, который он видел (до того, как приложение было уничтожено) отображается вместо «начального фрагмента» по умолчанию? Мне также нужно, чтобы мой фрагмент «меню» имел правильную позицию «выбрано», когда это происходит. Предпочтения приходят на ум, но у вас может быть лучшая идея? –
@MortenSalte: «Как я могу гарантировать, что когда пользователь запустит мое приложение, последний фрагмент, который он просматривал (до того, как приложение было уничтожено), отображается« - в 'onPause()' или 'onStop()', выписывает («SharedPreferences', file, database), которая будет сохраняться после завершения процесса. «Предпочтения приходят на ум, но у вас может быть лучшая идея?» - предпочтения будут типичным решением для чего-то подобного, но любой упорный магазин должен работать. – CommonsWare