I have an Activity that contains a number of Fragments that are swapped based on the selected item in a Navigation Drawer. I am trying to retain the current fragment across an orientation change by calling setRetainInstance(true) on the Fragment and then checking if that fragment exists in onCreate(...). However, the Fragment is always null when I try to get it on onCreate(...). I've been banging my head against my desk for hours over this. Can anyone spot a problem?
Relevant parts of activity
public class StartActivity {
private static final String MAIN_FRAGMENT_TAG = "mainFragment";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
...
if(savedInstanceState != null) {
Fragment f = getSupportFragmentManager().findFragmentByTag(MAIN_FRAGMENT_TAG);
if(f == null) {
// FRAGMENT IS ALWAYS NULL
switchToModeForPosition(...);
} else {
setupActionBarForPosition(...);
}
} else {
// Default to events view
switchToModeForPosition(0);
}
}
private void switchToModeForPosition(int position) {
Fragment fragment;
switch (position) {
default:
case 0: //events
fragment = new EventsByWeekFragment();
setupActionBarForEvents();
break;
case 1: //teams
fragment = new AllTeamsListFragment();
setupActionBarForTeams();
break;
case 2: //insights
fragment = new InsightsFragment();
setupActionBarForInsights();
break;
case 3:
startActivity(new Intent(this, SettingsActivity.class));
mDrawerLayout.closeDrawer(mDrawerList);
return;
}
fragment.setRetainInstance(true);
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, MAIN_FRAGMENT_TAG).commit();
}
}
use setRetainInstance(true)it in each Fragment class.
public void onCreated(Bundle savedInstanceState)
{
super.onCreated(savedInstanceState);
setRetainInstance(true);
}
Or
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
}
Related
I've already searched about this and found nothing, which helps me to solve my problem. In my Code I have a SpaceNavigationView (like BottomNavigationView) with five Fragments.
So in Fragment A, I've put a Recyclerview. If an item of the Recyclerview gets clicked, it will replace the current fragment with a new child fragment B.
In Fragment B I've set a Chronometer, which should count the time, when it gets pressed.
Now if I switch from Fragment B to Fragment C and go back to Fragment B, the Chronometer starts by zero, because the fragment was replaced.
I've tried to used onSaveInstanceState, so that it can be called when Fragment is recreated, but this doesn't work for me.
Here's a piece of the HomeActivity, which includes all the Fragments.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
init();
setFragment(fragmentHome);
navigationView.initWithSaveInstanceState(savedInstanceState);
navigationView.addSpaceItem(new SpaceItem("", R.drawable.bottom_baby));
navigationView.addSpaceItem(new SpaceItem("", R.drawable.bottom_advise));
navigationView.addSpaceItem(new SpaceItem("", R.drawable.ic_favorite_black_24dp));
navigationView.addSpaceItem(new SpaceItem("", R.drawable.ic_settings));
navigationView.setSpaceOnClickListener(new SpaceOnClickListener() {
#Override
public void onCentreButtonClick() {
setFragment(fragmentPlayground);
navigationView.setCentreButtonSelectable(true);
}
#Override
public void onItemClick(int itemIndex, String itemName) {
switch (itemIndex) {
case 0:
setFragment(fragmentHome);
return;
case 1:
setFragment(fragmentAdvising);
return;
case 2:
setFragment(fragmentMemories);
return;
case 3:
setFragment(fragmentSettings);
return;
default:
setFragment(fragmentHome);
return;
}
}
#Override
public void onItemReselected(int itemIndex, String itemName) {
Toast.makeText(HomeActivity.this, itemIndex + " " + itemName, Toast.LENGTH_SHORT).show();
}
});
}
private void setFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.container, fragment);
fragmentTransaction.commit();
}
So if i navigate now to FragmentHome and use the OnClickListener for Reycleritems, I will switch to Fragment_Chronograph
#Override
public void onItemClick(int position) {
switch (position) {
case 0:
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment_chronograph).commit();
}
So now I'm in Fragment_Chronograph and want to save the base for Chronograph. I will save the variable in onSavedInstanceState, which gets called when Activity is Paused.
#Override
public void onSaveInstanceState(#NonNull Bundle outState) {
startTime = SystemClock.elapsedRealtime() - chronometerLeft.getBase();
outState.putLong(CHRONOLEFT_TIME_SAVE_ID,startTime);
super.onSaveInstanceState(outState);
#Override
public void onPause() {
super.onPause();
onSaveInstanceState(new Bundle());
}
At the end i've put this code for restore in the OnCreate Method:
if (savedInstanceState != null) {
startTime = savedInstanceState.getLong(CHRONOLEFT_TIME_SAVE_ID,0);
chronometerLeft.setBase(startTime - SystemClock.elapsedRealtime());
chronometerLeft.start();
The OnSaveInstanceState gets called, but in the OnCreate Method it won't be called. I would be very thankful if someone could help me with this problem. I'm searching for days and didnt get a solution.
in set fragment method , first find fragment with id and then check if it's not null replace that
Fragment fragment = getSupportFragmentManager().findFragmentByTag(TAG_PLACEHOLDER);
if (fragment == null) {
fragment = new PlaceholderFragment();
}
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, fragment, TAG_PLACEHOLDER)
.commit();
Note : you must add tag to your fragments
#Arvin
FragmentHome ist initiated in the init() method;
private void init() {
navigationView = findViewById(R.id.space);
fragmentHome = new FragmentHome();
fragmentAdvising = new FragmentAdvising();
fragmentMemories = new FragmentMemories();
fragmentSettings = new FragmentSettings();
fragmentPlayground = new FragmentPlayground();
============= UPDATE =================
Problem was solved. I didn't have to use OnSavedInstanceState. I used a Helperclass to store the variable of the Chronometerbase. In OnCreate method i check if the variable is not null, then restore the before saved base.
I'm using HashMap of fragment's backstack. To save backstack and current fragment I use the code below:
public class MainActivity extends AppCompatActivity {
private HashMap<String, Stack<Fragment>> mStacks;
public static final String TAB_PROFILE = "tab_profile";
public static final String TAB_DASHBOARD = "tab_dashboard";
public static final String TAB_CHATS = "tab_chats";
public static final String TAB_SETTINGS = "tab_settings";
private String mCurrentTab;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupViews();
if (savedInstanceState != null) {
mCurrentTab = savedInstanceState.getString("currentTab");
mStacks = (HashMap<String, Stack<Fragment>>) savedInstanceState.getSerializable("stacks");
} else
selectedTab(TAB_DASHBOARD);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("stacks", mStacks);
outState.putString("currentTab", mCurrentTab);
}
private void setupViews() {
mStacks = new HashMap<>();
mStacks.put(TAB_PROFILE, new Stack<>());
mStacks.put(TAB_DASHBOARD, new Stack<>());
mStacks.put(TAB_CHATS, new Stack<>());
mStacks.put(TAB_SETTINGS, new Stack<>());
BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation);
bottomNavigationView.setSelectedItemId(R.id.action_dashboard);
BottomNavigationViewHelper.removeShiftMode(bottomNavigationView);
bottomNavigationView.setOnNavigationItemSelectedListener(item -> {
switch (item.getItemId()) {
case R.id.action_profile:
selectedTab(TAB_PROFILE);
return true;
case R.id.action_dashboard:
selectedTab(TAB_DASHBOARD);
return true;
case R.id.action_chats:
selectedTab(TAB_CHATS);
return true;
case R.id.action_settings:
selectedTab(TAB_SETTINGS);
return true;
}
return true;
});
bottomNavigationView.setOnNavigationItemReselectedListener(item -> {
if (mStacks.get(mCurrentTab).size() != 1) {
mStacks.get(mCurrentTab).clear();
switch (item.getItemId()) {
case R.id.action_profile:
selectedTab(TAB_PROFILE);
break;
case R.id.action_dashboard:
selectedTab(TAB_DASHBOARD);
break;
case R.id.action_chats:
selectedTab(TAB_CHATS);
break;
case R.id.action_settings:
selectedTab(TAB_SETTINGS);
break;
}
}
});
}
private void selectedTab(String tabId) {
mCurrentTab = tabId;
if(mStacks.get(tabId).size() == 0){
if(tabId.equals(TAB_PROFILE)){
Fragment fragment = new ProfileFragment();
Bundle args = new Bundle();
args.putSerializable("user", Globals.getCurrentUser());
fragment.setArguments(args);
pushFragments(tabId, fragment,true);
} else if(tabId.equals(TAB_DASHBOARD)){
pushFragments(tabId, new DashboardFragment(),true);
}else if(tabId.equals(TAB_CHATS)){
pushFragments(tabId, new GroupsFragment(),true);
}else if(tabId.equals(TAB_SETTINGS)){
pushFragments(tabId, new SettingsFragment(),true);
}
}else {
pushFragments(tabId, mStacks.get(tabId).lastElement(),false);
}
}
public void pushFragments(String tag, Fragment fragment, boolean shouldAdd){
if(shouldAdd)
mStacks.get(tag).push(fragment);
FragmentManager manager = getFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content, fragment);
ft.commit();
}
public void popFragments(){
Fragment fragment = mStacks.get(mCurrentTab).elementAt(mStacks.get(mCurrentTab).size() - 2);
mStacks.get(mCurrentTab).pop();
FragmentManager manager = getFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content, fragment);
ft.commit();
}
#Override
public void onBackPressed() {
if(mStacks.get(mCurrentTab).size() == 1){
finish();
return;
}
popFragments();
}
}
Set new fragments using
((MainActivity)context).pushFragments(MainActivity.TAB_CHATS, fragment,true);
Layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:background="#color/background_material_light"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/bottom_navigation"/>
<android.support.design.widget.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
app:itemBackground="#color/waPrimary"
app:itemIconTint="#color/white"
app:itemTextColor="#color/white"
app:menu="#menu/menu_bottom_navigation" />
Everything works fine on screen rotation, but application crashes with exception on application hide.
java.lang.RuntimeException: Parcel: unable to marshal value %FragmentName%{c985244 #2 id=0x7f090051}
As I read, it happens when one of the objects I'm trying to pass is not Parceable, but have no idea how to fix this. Any thoughts?
UPD
After I made all of my fragments Serializable, new exception throws
java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = %FragmentName%)
...
Caused by: java.io.NotSerializableException: android.support.v7.widget.RecyclerView
UPD2
Seems like a found a solution - transient property. Now I'm trying to make all non-serializeable objects transient.
UPD3
It helped, but I don't know is it efficient enough.
Here's my suggestion:
Your activity maintains a reference to the four fragments it wants for the bottom navigation toggling.
On toggling bottom navigation, you replace the current fragment in the activity fragment manager.
While on a given fragment, as you interact with the UI, you push things on to the fragment child fragment manager.
This way, each fragment maintains its own backstack automatically, you don't have to save any state, and it all Just Works™.
Some sample code that might help.
public class MainActivity extends AppCompatActivity {
private Fragment mProfileFragment;
private Fragment mDashboardFragment;
private Fragment mChatsFragment;
private Fragment mSettingsFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
// Init fragments
}
else {
// Find last active fragments in fragment manager
}
setupViews();
}
private void setupViews() {
BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_navigation);
bottomNavigationView.setSelectedItemId(R.id.action_dashboard);
BottomNavigationViewHelper.removeShiftMode(bottomNavigationView);
bottomNavigationView.setOnNavigationItemSelectedListener(item -> {
Fragment fragment;
switch (item.getItemId()) {
case R.id.action_profile:
fragment = mProfileFragment;
break;
case R.id.action_dashboard:
fragment = mDashboardFragment;
break;
case R.id.action_chats:
fragment = mChatsFragment;
break;
case R.id.action_settings:
fragment = mSettingsFragment;
break;
}
// Replace the currently active fragment which will be
// managing its own backstack
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frament_container, fragment)
.commit();
});
}
}
And one of your fragments would push stuff on its own stack like this:
public class ProfileFragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.id.fragment_layout, container, false);
Button button = view.findViewById(R.id.some_button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment someFragmentToPush = new SomeFragmentToPush();
// Use the child fragment manager to keep UI
// local to this fragment instance, adding to backstack
// for automatic popping on pressing back
getChildFragmentManager().beginTransaction()
.add(R.id.fragment_layout, someFragmentToPush)
.addToBackStack(null)
.commit();
}
});
return view;
}
}
Hope that helps!
I'm using NavigationDrawer with some fragments, the problem is when I'm in a fragment and hit the back button, it makes the app close, then I have to open it again, put my username and password all over again to use the app, how can I prevent that from happen?
public class NavigationMain extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
}
public void setFragmentList(int posicao) {
Fragment fragment = null;
switch (posicao) {
case 0:
fragment = new MainFragment();
break;
case 1:
fragment = new MensagensFragment();
break;
case 2:
fragment = new EscolasFragment();
break;
case 3:
fragment = new AutorizadasFragment();
break;
case 4:
fragment = new CadastroFragment();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
// update selected item and title, then close the drawer
navigationAdapter.resetarCheck();
navigationAdapter.setChecked(posicao, true);
layoutDrawer.closeDrawer(linearDrawer);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
}
#Override
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
//additional code
} else {
getFragmentManager().popBackStack();
}
}
I think you missed to add the fragment transaction in your back stack. Try the following:
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).addToBackStack(null).commit();
I have see this question asked here more than one time but I can't figure it out how to solve for my case.
I have an app that the user does this:
1 - Open the navigationDrawer and selects one option (a fragment is created) (I'm here selecting the second option);
public void selectItem(int position) {
Fragment fragment = null;
switch (position) {
case FRAGMENT_OPTION1:
...
break;
case FRAGMENT_OPTION2:
fragment = ControlPanelFragment.newInstance();
break;
...
case FRAGMENT_OPTIONN:
...
return;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.fragment_container, fragment).commitAllowingStateLoss();
}
}
2 - The selected option (ControlPanelFragment) gets loaded:
2.1 - Control panel has tabs and an iconpager. For each pager page and for each tab a new fragment is created. I have 3 tabs and 3 pages so 9 fragments are created;
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (savedInstanceState != null) {
currentControlPanelOption = savedInstanceState.getInt("currentControlPanelOption", currentControlPanelOption);
currentControlPanelTab = savedInstanceState.getInt("currentControlPanelTab", currentControlPanelTab);
}
setControlPanelTabs();
setIconPager();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("currentControlPanelOption", pager.getCurrentItem());
outState.putInt("currentControlPanelTab", mTabHost.getCurrentTab());
}
3 - In the setIconPager(); I have this code:
pager = (ViewPager) view.findViewById(R.id.pager);
cPanelPagerAdapter = new ControlPanelPagerAdapter(getChildFragmentManager());
pager.setOffscreenPageLimit(2);
pager.setAdapter(cPanelPagerAdapter);
where ControlPanelPagerAdapter has this code:
public Fragment getItem(int index) {
Fragment fragment;
switch (index) {
case 1:
fragment = FragmentA.newInstance();
break;
case 2:
fragment = FragmentB.newInstance();
break;
case 3:
fragment = FragmentC.newInstance();
break;
default:
fragment = null;
break;
}
...
return fragment;
}
4 - FragmentA, FragmentB and FragmentC have almost the same code:
public static FragmentA newInstance() {
return new FragmentA();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_placeholder, container, false);
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (savedInstanceState == null) {
fragmentA_Data = new FragmentADetail[3];
createTabInstance(0);
} else {
fragmentA_Data = (FragmentADetail[]) savedInstanceState.getSerializable("Data");
return;
}
}
private void createTabInstance(int tab) {
new FragmentADetail();
fragment = FragmentADetail.newInstance(tab);
Bundle args = new Bundle();
args.putInt("tab", tab);
fragment.setArguments(args);
fragmentA_Data[tab] = fragment;
FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_placeholder, fragmentA_Data[tab]);
fragmentTransaction.commitAllowingStateLoss();
}
public void getTabData(int tab) {
if (fragmentA_Data[tab] == null) {
createStoreTimePeriodInstance(tab);
} else {
if (fragmentA_Data[tab].getArguments() == null) {
Bundle args = new Bundle();
args.putInt("tab", tab);
fragmentA_Data[tab].setArguments(args);
}
FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_placeholder, fragmentA_Data[tab]);
fragmentTransaction.commitAllowingStateLoss();
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("data", fragmentA_Data);
}
5 - Finally, FragmentADetail has this code:
public static FragmentADetail newInstance(int tab) {
selectedTab = tab;
return new FragmentADetail();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.details_fragment, container, false);
...
if (savedInstanceState != null) {
selectedTab = savedInstanceState.getInt("selectedTab");
}
...
}
public void getTabData(int tab) {
//This is where I'm getting the data that populates the layout
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("selectedTab", selectedTab);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
getTabData(args.getInt("tab"));
}
}
Now, imagine I'm on FragmentA with the third tab selected. If I rotate the screen I have this sequence of events:
ControlPanelFragment onSaveInstanceState saves the current tab and current fragment
FragmentA onSaveInstanceState saves the tabs fragments for the pager
navigationDrawer second option gets again called fragment = ControlPanelFragment.newInstance();
ControlPanelFragment onViewCreated is called and I can get the saved data information and a new pager and tabs are created
FragmentA onViewCreated is called and I can extract the saved data
FragmentADetail onActivityCreated gets the saved data and loads the data correctelly (at least I think)
And from now a second set of methods is called the second time and the data that was previously saved is reseted and so it now displays wrong data
ControlPanelFragment onSaveInstanceState but now the savedInstanceState is null
ControlPanelPagerAdapter getItem is called instantiating the 3 fragments
FragmentA onSaveInstanceState its now called but savedInstanceState is null
FragmentADetail onActivityCreated is called but now the tab = 0
Can someone explain-me how can I stop steps 7 to 10 from happening?
I figure out what was my problem.
When I was doing:
case FRAGMENT_OPTION2:
fragment = ControlPanelFragment.newInstance();
break;
I was creating a fragment and when I rotated the screen selectItem(int position) was again called so a new instance of the same object was created thus the steps 7 and following. The solution was to check if the fragment was already created and use him instead of creating a new one.
I've saved the initial fragment with a tag and them looked for that tag. If the tag existed, use that fragment otherwise create a new one.
public void selectItem(int position) {
Fragment fragment = null;
switch (position) {
case FRAGMENT_OPTION1:
...
break;
case FRAGMENT_OPTION2:
fragment = getSupportFragmentManager().findFragmentByTag(String.valueOf(position));
if (fragment == null) {
fragment = ControlPanelFragment.newInstance();
}
break;
...
case FRAGMENT_OPTIONN:
...
return;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.fragment_container, fragment,
String.valueOf(position)).commitAllowingStateLoss();
}
}
I am working with fragments and pushing new fragments on the backstack but when I rotate the device twice the fragment's onCreateView, onActivityCreated, and so on in the fragment life cycle methods are never called leaving a blank screen. This only occurs when a fragment has been added to the backstack or returning to the first fragment in the backstack.
Here is my activity's fragment handling methods:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Injection
MormonChannel.injectActivity(this);
setDrawerIndicatorEnabled(true);
// Do not set currentNavigationItem here.
NavigationItemSelectedEvent.NavigationItem navItem = null;
Intent intent = getIntent();
if (intent != null) {
navItem = (NavigationItemSelectedEvent.NavigationItem)
intent.getSerializableExtra(EXTRA_NAV_ITEM);
}
if (savedInstanceState == null) {
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().replace(R.id.container, new FeatureListFragment()).commit();
if (navItem != null) {
onNavigationItemSelected(new NavigationItemSelectedEvent(navItem));
} else {
currentNavigationItem = NavigationItemSelectedEvent.NavigationItem.FEATURES;
}
}
}
#Subscribe
public void onNavigationItemSelected(NavigationItemSelectedEvent event) {
if (currentNavigationItem == event.getNavigationItem()) {
return;
}
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack();
NavigationItemSelectedEvent.NavigationItem navigationItem = event.getNavigationItem();
String name = navigationItem.getName();
switch (navigationItem) {
default:
case FEATURES:
// Nothing needs to be done it is already there.
break;
case AUDIO:
fragmentManager.beginTransaction().replace(R.id.container,
CollectionListFragment.newInstance(prefs.getLanguageId(), prefs.getAudioCollectionId()))
.addToBackStack
(name).commit();
break;
case VIDEO:
fragmentManager.beginTransaction().replace(R.id.container,
CollectionListFragment.newInstance(prefs.getLanguageId(), prefs.getVideoCollectionId()))
.addToBackStack(name).commit();
break;
case RADIO:
fragmentManager.beginTransaction().replace(R.id.container,
CollectionListFragment.newInstance(prefs.getLanguageId(), prefs.getRadioCollectionId()))
.addToBackStack(name).commit();
break;
case HISTORY:
fragmentManager.beginTransaction().replace(R.id.container, new HistoryFragment()).addToBackStack(name).commit();
break;
case DOWNLOADS:
fragmentManager.beginTransaction().replace(R.id.container, new DownloadsFragment()).addToBackStack(name).commit();
break;
case PLAYLISTS:
fragmentManager.beginTransaction().replace(R.id.container, new PlaylistFragment()).addToBackStack(name).commit();
break;
}
currentNavigationItem = navigationItem;
}
Here is my CollectionListFragment Code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MormonChannel.injectFragment(this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.collection_list_fragment, container, false);
ButterKnife.inject(this, v);
return v;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listView.setDividerHeight(0);
listView.setFastScrollEnabled(true);
Bundle args = getArguments();
if (args != null) {
languageId = args.getLong(ARG_LANGUAGE_ID, -1L);
collectionId = args.getLong(ARG_COLLECTION_ID, -1L);
if (args.containsKey(ARG_SORT)) {
sort = (Sort) args.getSerializable(ARG_SORT);
}
}
if (collectionId == -1L || languageId == -1L) {
// TODO Implement Empty Collection Text
} else {
collection = collectionManager.findByCollectionId(languageId, collectionId);
getLoaderManager().initLoader(LOADER_ID, null, this);
}
titleEvent = new TitleChangeEvent(collection != null ? collection.getTitle() : getString(R.string.app_name));
bus.post(titleEvent);
}
Manifest for activity:
<activity
android:name=".activity.MainActivity"
android:launchMode="singleTask">
<meta-data
android:name="android.app.default_searchable"
android:value=".activity.SearchActivity"/>
</activity>
In your CollectionListFragment Code, add call to setRetainInstance() method in the onCreate() method, with true as its argument:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
MormonChannel.injectFragment(this);
}
Using setRetainInstance(true) ensures that when configuration changes occur activity will be killed but android will not destroy the fragment it is hosting.
Instead android will save the fragment state and detach the fragment from the activity. Also it wont destroy the fragment and so it wont create it later when hosting activity is created. So fragment will not receive calls to its onDestroy() and onCreate() methods.