Model-View-ViewModel (MVVM)
One Activity, one view
One Activity
holds one view (Fragment
) and ViewModel. I want to retain the ViewModel instance when the screen is rotated, but create the new one when backs from the other Activity
.
MainActivity
public class MainActivity extends AppCompatActivity { private static final String MAIN_VIEWMODEL_TAG = "MAIN_VIEWMODEL_TAG"; @Inject Lazy<MainViewModel> viewModelProvider; @Inject Lazy<MainFragment> fragmentProvider; @Override protected void onCreate(Bundle savedInstanceState) { AndroidInjection.inject(this); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findOrCreateViewThenDisplayIt(findOrCreateViewModel(MAIN_VIEWMODEL_TAG)); } private void findOrCreateViewThenDisplayIt(@NonNull MainViewModel viewModel) { BaseView<MainViewModel> baseView = findView(); if (baseView == null) { baseView = fragmentProvider.get(); baseView.setViewModel(viewModel); ActivityUtils.addFragmentToActivity( getSupportFragmentManager(), baseView, R.id.contentFrame); } else { baseView.setViewModel(viewModel); } } @SuppressWarnings("unchecked") @Nullable private BaseView<MainViewModel> findView() { return (BaseView<MainViewModel>) getSupportFragmentManager() .findFragmentById(R.id.contentFrame); } @NonNull private MainViewModel findOrCreateViewModel(@NonNull String tag) { // In a configuration change we might have a ViewModel present. It's retained using the // Fragment Manager. @SuppressWarnings("unchecked") ViewModelHolder<MainViewModel> retainedViewModel = (ViewModelHolder<MainViewModel>) getSupportFragmentManager().findFragmentByTag(tag); if (retainedViewModel != null && retainedViewModel.getViewmodel() != null) { // If the model was retained, return it. return retainedViewModel.getViewmodel(); } else { // There is no ViewModel yet, create it. MainViewModel viewModel = viewModelProvider.get(); // and bind it to this Activity's lifecycle using the Fragment Manager. ActivityUtils.addFragmentToActivity( getSupportFragmentManager(), ViewModelHolder.createContainer(viewModel), tag); return viewModel; } } }
MainViewModel
@ActivityScoped public class MainViewModel extends BaseObservable implements BaseViewModel { @Inject MainViewModel() { } }
Should set its scope same as
Activity
.MainFragment
@ActivityScoped public class MainFragment extends BaseView<MainViewModel> { @Inject public MainFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { FragmentMainBinding binding = DataBindingUtil .inflate(inflater, R.layout.fragment_main, container, false); binding.setViewModel(viewModel); return binding.getRoot(); } }
LogCat
I/main: onCreate() D/main: get ViewModel from Dagger! I/MainViewModel: MainViewModel() D/main: viewModel is com.hsy.d.main.MainViewModel@96bf940 D/main: get View from Dagger! I/MainFragment: MainFragment() I/MainFragment: onCreate() I/MainFragment: onCreateView() I/main: onStart() D/MainFragment: onResume(): viewModel is com.hsy.d.main.MainViewModel@96bf940 // rotation I/main: onStop() I/MainFragment: onDestroy() I/main: onDestroy() I/main: onCreate() I/MainFragment: MainFragment() I/MainFragment: onCreate() D/main: ViewModel was retained D/main: viewModel is com.hsy.d.main.MainViewModel@96bf940 D/main: View was retained I/MainFragment: onCreateView() I/main: onStart() D/MainFragment: onResume(): viewModel is com.hsy.d.main.MainViewModel@96bf940 // start other Activity and finish self I/main: onStop() I/MainFragment: onDestroy() I/main: onDestroy() // back to MainActivity I/main: onCreate() D/main: get ViewModel from Dagger! I/MainViewModel: MainViewModel() D/main: viewModel is com.hsy.d.main.MainViewModel@696feeb D/main: get View from Dagger! I/MainFragment: MainFragment() I/MainFragment: onCreate() I/MainFragment: onCreateView() I/main: onStart() D/MainFragment: onResume(): viewModel is com.hsy.d.main.MainViewModel@696feeb