0

I've an activity with a viewpager which displays several fragments (dynamically created).

On the Fragments I've observable fields. So far so good. The issue I face right now is that once I do an device rotation when the Activity with the fragments is displayed the observable fields are not in the code but within the fragment the fields are null and therefore won't be binded.

Here is my Fragment code:

public class MyFragment extends Fragment
{
  private FragmentSwipeBinding _binding;
  public ObservableField<MyViewModel> observableMyViewModel = new ObservableField<MyViewModel>();

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
  {
    _binding = DataBindingUtil.inflate(inflater, R.layout.fragment_swipe, container, false);
    _binding.setViewModel(this);
    _binding.executePendingBindings();

    notifyViewModelChanged();

    // Other code using binding
    _binding....

    return _binding.getRoot();
  }


  private void notifyViewModelChanged()
  {
    MyViewModel viewmodel = observableMyViewModel.get();
    if(viewmodel != null)
    {
      viewmodel.update();
      observableMyViewModel.notifyChange();
    }
  }
}

And in my Activity I create new fragments like that

MyFragment myFragment = new MyFragment();
MyViewModel viewmodel = _myViewModels.get(i);
myFragment.observableMyViewModel.set(viewmodel);

Any hint what's wrong?


Update

Ok I changed in my Activity the code like that:

@Override
protected void onCreate(Bundle savedInstanceState)
{
  super.onCreate(savedInstanceState);

  // other code

  if(savedInstanceState != null)
  {
    //Restore the fragment's instance
    for(int i = 0; i < _myViewModels.size(); i++)
    {
      MyFragment myFragment;
      if(i < getSupportFragmentManager().getFragments().size())
      {
        myFragment = (MyFragment) getSupportFragmentManager().getFragment(savedInstanceState, "FragmentName" + i);
      }
      else
      {
        myFragment = new MyFragment();
        MyViewModel viewmodel = _myViewModels.get(i);
        myFragment.observableMyViewModel .set(viewmodel);
      }
      myPagerAdapter.addFragment(myFragment,_myViewModels.get(i).getDescription());
    }
  }
  else
  {
    for(int i = 0; i < _myViewModels.size(); i++)
    {
      MyFragment myFragment = new MyFragment();
      MyViewModel viewmodel = _myViewModels.get(i);
      myFragment.observableMyViewModel .set(viewmodel);
      myPagerAdapter.addFragment(myFragment, viewmodel.getDescription());
    }
  }
}

@Override
protected void onSaveInstanceState(Bundle outState)
{
  super.onSaveInstanceState(outState);
  //Save the fragment's instance
  for(int i = 0; i < getSupportFragmentManager().getFragments().size(); i++)
  {
    getSupportFragmentManager().putFragment(outState, "FragmentName" + i, getSupportFragmentManager().getFragments().get(i));
  }
}
Bruno Bieri
  • 9,724
  • 11
  • 63
  • 92
  • Config change isn't handled by data binding. – Anatolii Jun 29 '18 at 09:35
  • Is your **MyViewModel** implements **android.arch.lifecycle.ViewModel** – Brijesh Joshi Jun 29 '18 at 09:51
  • @BrijeshJoshi no it doesn't. What would be the benefit of it? – Bruno Bieri Jun 29 '18 at 11:00
  • @BrunoBieri android.arch.lifecycle.ViewModel is a class that is responsible for preparing and managing the data for an Activity or a Fragment. It also handles the communication of the Activity / Fragment with the rest of the application (e.g. calling the business logic classes). – Brijesh Joshi Jun 29 '18 at 11:02
  • @BrijeshJoshi Thanks for the help. I mean I read also the description of the official documentation about the ViewModel (https://developer.android.com/reference/android/arch/lifecycle/ViewModel). But I would like to understand what it means for my case. Can you help me here? – Bruno Bieri Jun 29 '18 at 11:06
  • @BrunoBieri as i read in the documentation **The ViewModel class allows data to survive configuration changes such as screen rotations.** So it will help you in that sense. Furthermore I can prepare the demo for you with your class. if that's what you needed – Brijesh Joshi Jun 29 '18 at 11:10
  • https://medium.com/google-developers/viewmodels-a-simple-example-ed5ac416317e check this example i think it will help you – Brijesh Joshi Jun 29 '18 at 11:21
  • @user8035311 How is the way to go to handle config changed with data binding? Maybe you've a look at my update. – Bruno Bieri Jun 29 '18 at 12:20
  • 1
    I would do it as @Brijesh Joshi suggested by using ViewModel from ArchitectureComponents. – Anatolii Jun 29 '18 at 12:24
  • Okay So i'm keeping that link in the answer box so that in future someone can also follow it. – Brijesh Joshi Jun 29 '18 at 12:25

2 Answers2

1

On configuration change (such as device rotation) you are loosing fields. For that reason we use onSaveInstanceState onRestoreInstanceState to save and restore fields.

Read more at: https://stackoverflow.com/a/30011971/4183017

Ioane Sharvadze
  • 2,118
  • 21
  • 35
  • Thanks for the answer. Can you explain a little bit more what do you mean by loosing fields? what happens to observable fields when a fragment is destroyed and rebuild at device rotation? – Bruno Bieri Jun 29 '18 at 10:59
  • Actually "loosing fields" was innacurate. When fragment is destroyed, it is garbage collected i.e. deleted from memory. Thus after rotation, new fragment is created. Only thing you get is saved state from old fragment, that is represented as bundle and passed in 'onCreate'. – Ioane Sharvadze Jun 30 '18 at 11:56
  • Actually this link https://stackoverflow.com/a/17135346/1306012 in your linked answer helped me to implement it correctly. Maybe update your answer accordingly. – Bruno Bieri Jul 05 '18 at 07:53
0

We can achieve this with the help of Android Architecture Component ViewModel. As I read in the documentation The ViewModel class allows data to survive configuration changes such as screen rotations.

check this example i think it will help you

Brijesh Joshi
  • 1,817
  • 1
  • 9
  • 24