4

CURRENT SCENARIO

In my app I am having navigation drawer with fragments. Everything works fine in portrait mode.

PROBLEM

Suppose when in portrait mode I select second item from navigation drawer. It loads perfectly but when I rotate my phone to landscape mode, first fragment from the navigation menu gets loaded instead of second.

I know I have to save instance for fragment but I don't know how to do it and should I do it in main activity or in fragment itself

Vivek Mishra
  • 5,669
  • 9
  • 46
  • 84

5 Answers5

3

You should do that in your Fragment.

Just follow these links:

Android - save/restore fragment state

Or perhaps:

Once for all, how to correctly save instance state of Fragments in back stack?

Also, let's mention about onRestoreInstanceState, Fragment's doesn't have that method.So, you should use onActivityCreated which receives a bundle with the saved instance state (or null).

Take a look at the docs:

http://developer.android.com/reference/android/app/Fragment.html#onActivityCreated(android.os.Bundle)

Community
  • 1
  • 1
ʍѳђઽ૯ท
  • 16,646
  • 7
  • 53
  • 108
  • I have used setRetainState already in onActivityCreated. What else is required?? – Vivek Mishra Jan 24 '16 at 17:30
  • Check this link :http://stackoverflow.com/questions/11182180/understanding-fragments-setretaininstanceboolean – ʍѳђઽ૯ท Jan 24 '16 at 17:31
  • 2
    Thanks for pointing to the link I got my code working with certain modification. I was passing hard coded int to display fragment method in main activity. So in save instance state i just saved the position and then loaded fragment of that position in onCreate – Vivek Mishra Jan 24 '16 at 17:41
3

I answered the same question in this thread:

How to keep the same fragment when activity restarts due to orientation change in a Navigation Drawer Activity

I tried to explain why the solution I give works, so if you're interested check it out.

To solve the problem I simply put the code that inflates the initial fragment inside an if (in the OnCreate of the navigation drawer activity):

super.onCreate(savedInstanceState);
if(savedInstanceState==null){
    FragmentManager fM = getSupportFragmentManager();
    fM.beginTransaction().replace(R.id.NavDrawContent,new home_fragment()).commit();
}

so that it doesn't inflate the first fragment when we change the orientation while in the second

4444borja
  • 131
  • 1
  • 6
1

I found a better solution using the new tool called ViewModel class. When the screen rotates, it automatically destroys de activity and creates it again, so we lost the focus of the last fragment selected. ViewModel helps us keeping the data and it's so useful for forms too.

  1. Create a class called MainActivityViewModel.kt
  2. Put this code inside:

    class MainActivityViewModel : ViewModel() { var menuItem : Int = R.id.nav_inicio }


I'm choosing R.id.nav_inicio as default menu item, modify it depending of your activity_main_drawer.xml (Default name for android studio)

3. Then, declare it into your MainActivity with the navigation drawer:

lateinit var vm : MainActivityViewModel

  1. Add this line into your onCreate override method:

    vm = ViewModelProviders.of(this).get(MainActivityViewModel::class.java)

  2. Then create a function that loads the default Fragment:

    fun loadDefaultFragment() { when (vm.menuItem) { R.id.nav_inicio -> { fab.hide() val fragment = InicioFragment() val manager = supportFragmentManager manager.beginTransaction().replace(R.id.content_main, fragment, fragment.getTag()).commit() } R.id.nav_puntosventa -> { fab.show() val fragment = ListaPuntosFragment() val manager = supportFragmentManager manager.beginTransaction().replace(R.id.content_main, fragment, fragment.getTag()).commit() } else -> { // default fragment if you consider necessary } } }

this function must be called into your onCreate method after the initialization of the ViewModel.

6. Finally, we have to update the viewModel value each time we select a new menu item, so modify the override function onNavigationItemSelected adding it at the beginning:

override fun onNavigationItemSelected(item: MenuItem): Boolean { // Handle navigation view item clicks here. vm.menuItem = item.itemId // rest of the code ... }

Now , when you rotate your screen, de viewmodel value save the position, you can use it with forms maybe.

1

There is a problem with nav controller backstack after changed config

In your Activity with fragment: try saving the nav controller state before changing the configuration. After changing the configuration, add it back to the nav controller again. Like:

override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putBundle("nav_state", fragment.findNavController().saveState())}

override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
fragment.findNavController().restoreState(savedInstanceState.getBundle("nav_state"))}

Thats my case

Daniel Pína
  • 348
  • 2
  • 7
0

The new Android Architecture components introduces a ViewModel class which helps create lifecycle aware components. It solves most of these issues regarding lifecycle management. If you are using Java code in your project, you could introduce a ViewModel class. Follow these steps:

  1. add this to your build.gradle(app module)

    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
    
  2. add this to your build.gradle(project module)

    dependencies {
    
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72"
    }
    
  3. Create a new MainActivityViewModel.kt class with the code below

    class MainActivityViewModel : ViewModel() {
    var menuItem: Int = R.id.nav_home
    }
    
  4. In your MainActivity.java add the following at the top of the class

    private MainActivityViewModel vm;
    

    and in your MainActivity.java onCreate method

    vm = new ViewModelProvider(this).get(MainActivityViewModel.class);
    loadDefaultFragment();
    
  5. Now create a method loadFragment() in MainActivity.java with the code below

    private void loadFragment(Fragment fragment) {
    // load fragment
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.contentMainLayout, fragment);
    transaction.addToBackStack(null);
    transaction.commit();
    }
    
  6. Create another method loadDefaultFragment() in your MainActivity.java

    private void loadDefaultFragment(){
    if(vm.getMenuItem()==R.id.nav_home){
        fragment = new HomeFragment();
        loadFragment(fragment);
    }else if(vm.getMenuItem()==R.id.nav_another_fragment){
        fragment = new AnotherFragment();
        loadFragment(fragment);
    }
    //you can add or exclude other  fragments here depending on your requirements
    }
    
  7. Finally, we have to update the viewModel value each time we select a new menu item, so modify the override method onNavigationItemSelected adding it at the beginning:

    // Handle navigation view item clicks here.
    vm.setMenuItem(item.getItemId());
    
Tom Munyiri
  • 156
  • 2
  • 5