Skip to content

Commit 807a579

Browse files
author
Daniel Novak
committed
Retain viewmodels within activity
1 parent 764ec9f commit 807a579

File tree

6 files changed

+83
-22
lines changed

6 files changed

+83
-22
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package eu.inloop.viewmodel;
2+
3+
/**
4+
* Your {@link android.app.Activity} must implement this interface if
5+
* any of the contained Fragments the {@link eu.inloop.viewmodel.ViewModelHelper}
6+
*/
7+
public interface IViewModelProvider {
8+
9+
/**
10+
* See {@link eu.inloop.viewmodel.base.ViewModelBaseActivity} on how to implement.
11+
* @return
12+
*/
13+
public ViewModelProvider getViewModelProvider();
14+
}

library/src/main/java/eu/inloop/viewmodel/ViewModelHelper.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ public class ViewModelHelper<T extends IView, R extends AbstractViewModel<T>> {
2020
/**
2121
* Call from {@link android.app.Activity#onCreate(android.os.Bundle)} or
2222
* {@link android.support.v4.app.Fragment#onCreate(android.os.Bundle)}
23+
* @param activity parent activity
2324
* @param savedInstanceState savedInstance state from {@link Activity#onCreate(Bundle)} or
2425
* {@link Fragment#onCreate(Bundle)}
2526
* @param viewModelClass the {@link Class} of your ViewModel
2627
* @param arguments pass {@link Fragment#getArguments()} or
2728
* {@link Activity#getIntent()}.{@link Intent#getExtras() getExtras()}
2829
*/
29-
public void onCreate(@Nullable Bundle savedInstanceState,
30+
public void onCreate(@NonNull Activity activity,
31+
@Nullable Bundle savedInstanceState,
3032
@Nullable Class<? extends AbstractViewModel<T>> viewModelClass,
3133
@Nullable Bundle arguments) {
3234
// no viewmodel for this fragment
@@ -44,7 +46,7 @@ public void onCreate(@Nullable Bundle savedInstanceState,
4446
}
4547

4648
// get model instance for this screen
47-
final ViewModelProvider.ViewModelWrapper<T> viewModelWrapper = ViewModelProvider.getInstance().getViewModel(mScreenId, viewModelClass);
49+
final ViewModelProvider.ViewModelWrapper<T> viewModelWrapper = getViewModelProvider(activity).getViewModelProvider().getViewModel(mScreenId, viewModelClass);
4850
//noinspection unchecked
4951
mViewModel = (R) viewModelWrapper.viewModel;
5052

@@ -83,7 +85,7 @@ public void onDestroyView(@NonNull Fragment fragment) {
8385
}
8486
mViewModel.clearView();
8587
if (fragment.getActivity() != null && fragment.getActivity().isFinishing()) {
86-
removeViewModel();
88+
removeViewModel(fragment.getActivity());
8789
}
8890
}
8991

@@ -98,14 +100,14 @@ public void onDestroy(@NonNull Fragment fragment) {
98100
return;
99101
}
100102
if (fragment.getActivity().isFinishing()) {
101-
removeViewModel();
103+
removeViewModel(fragment.getActivity());
102104
} else if (fragment.isRemoving() && !mOnSaveInstanceCalled) {
103105
// The fragment can be still in backstack even if isRemoving() is true.
104106
// We check mOnSaveInstanceCalled - if this was not called then the fragment is totally removed.
105107
if (BuildConfig.DEBUG) {
106108
Log.d("mode", "Removing viewmodel - fragment replaced");
107109
}
108-
removeViewModel();
110+
removeViewModel(fragment.getActivity());
109111
}
110112
}
111113

@@ -121,7 +123,7 @@ public void onDestroy(@NonNull Activity activity) {
121123
}
122124
mViewModel.clearView();
123125
if (activity.isFinishing()) {
124-
removeViewModel();
126+
removeViewModel(activity);
125127
}
126128
}
127129

@@ -167,11 +169,18 @@ public void onSaveInstanceState(@NonNull Bundle bundle) {
167169
}
168170
}
169171

170-
private void removeViewModel() {
172+
private void removeViewModel(@NonNull final Activity activity) {
171173
if (!mModelRemoved) {
172-
ViewModelProvider.getInstance().remove(mScreenId);
174+
getViewModelProvider(activity).getViewModelProvider().remove(mScreenId);
173175
mViewModel.onModelRemoved();
174176
mModelRemoved = true;
175177
}
176178
}
179+
180+
private IViewModelProvider getViewModelProvider(@NonNull Activity activity) {
181+
if (!(activity instanceof IViewModelProvider)) {
182+
throw new IllegalStateException("Your activity must implement IViewModelProvider");
183+
}
184+
return ((IViewModelProvider) activity);
185+
}
177186
}

library/src/main/java/eu/inloop/viewmodel/ViewModelProvider.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package eu.inloop.viewmodel;
2+
import android.app.Activity;
23
import android.support.annotation.NonNull;
4+
import android.support.v4.app.FragmentActivity;
35
import android.util.SparseArray;
46

57
import java.util.HashMap;
@@ -12,22 +14,37 @@
1214
*/
1315
public class ViewModelProvider {
1416

15-
private static final ViewModelProvider sInstance = new ViewModelProvider();
16-
1717
private final HashMap<String, AbstractViewModel<? extends IView>> mViewModelCache;
1818

19-
private ViewModelProvider() {
20-
mViewModelCache = new HashMap<>();
19+
public static ViewModelProvider newInstance(@NonNull final FragmentActivity activity) {
20+
if (activity.getLastCustomNonConfigurationInstance() == null) {
21+
return new ViewModelProvider();
22+
} else {
23+
return (ViewModelProvider) activity.getLastCustomNonConfigurationInstance();
24+
}
2125
}
2226

23-
public static ViewModelProvider getInstance() {
24-
return sInstance;
27+
@Deprecated
28+
public static ViewModelProvider newInstance(@NonNull final Activity activity) {
29+
if (activity.getLastNonConfigurationInstance() == null) {
30+
return new ViewModelProvider();
31+
} else {
32+
return (ViewModelProvider) activity.getLastNonConfigurationInstance();
33+
}
34+
}
35+
36+
private ViewModelProvider() {
37+
mViewModelCache = new HashMap<>();
2538
}
2639

2740
public synchronized void remove(String modeIdentifier) {
2841
mViewModelCache.remove(modeIdentifier);
2942
}
3043

44+
public synchronized void removeAllViewModels() {
45+
mViewModelCache.clear();
46+
}
47+
3148
@SuppressWarnings("unchecked")
3249
@NonNull
3350
public synchronized <T extends IView> ViewModelWrapper<T> getViewModel(String modelIdentifier, @NonNull Class<? extends AbstractViewModel<T>> viewModelClass) {

library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseActivity.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,21 @@
66

77
import eu.inloop.viewmodel.AbstractViewModel;
88
import eu.inloop.viewmodel.IView;
9+
import eu.inloop.viewmodel.IViewModelProvider;
910
import eu.inloop.viewmodel.ViewModelHelper;
11+
import eu.inloop.viewmodel.ViewModelProvider;
1012

11-
public abstract class ViewModelBaseActivity<T extends IView, R extends AbstractViewModel<T>> extends AppCompatActivity implements IView {
13+
public abstract class ViewModelBaseActivity<T extends IView, R extends AbstractViewModel<T>> extends AppCompatActivity implements IView, IViewModelProvider {
1214

1315
private final ViewModelHelper<T, R> mViewModeHelper = new ViewModelHelper<>();
16+
private ViewModelProvider mViewModelProvider;
1417

1518
@Override
1619
protected void onCreate(Bundle savedInstanceState) {
20+
//This code must be execute prior to super.onCreate()
21+
mViewModelProvider = ViewModelProvider.newInstance(this);
1722
super.onCreate(savedInstanceState);
18-
mViewModeHelper.onCreate(savedInstanceState, getViewModelClass(), getIntent().getExtras());
23+
mViewModeHelper.onCreate(this, savedInstanceState, getViewModelClass(), getIntent().getExtras());
1924
}
2025

2126
/**
@@ -28,6 +33,11 @@ public void setModelView(@NonNull T view) {
2833

2934
public abstract Class<R> getViewModelClass();
3035

36+
@Override
37+
public Object onRetainCustomNonConfigurationInstance() {
38+
return mViewModelProvider;
39+
}
40+
3141
@Override
3242
public void onSaveInstanceState(Bundle outState) {
3343
super.onSaveInstanceState(outState);
@@ -44,6 +54,9 @@ public void onStart() {
4454
public void onStop() {
4555
super.onStop();
4656
mViewModeHelper.onStop();
57+
if (isFinishing()) {
58+
mViewModelProvider.removeAllViewModels();
59+
}
4760
}
4861

4962
@Override
@@ -56,4 +69,9 @@ public void onDestroy() {
5669
public R getViewModel() {
5770
return mViewModeHelper.getViewModel();
5871
}
72+
73+
@Override
74+
public ViewModelProvider getViewModelProvider() {
75+
return mViewModelProvider;
76+
}
5977
}

library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseFragment.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import android.os.Bundle;
44
import android.support.annotation.NonNull;
5-
import android.support.annotation.Nullable;
65
import android.support.v4.app.Fragment;
76
import android.view.View;
87

@@ -17,7 +16,7 @@ public abstract class ViewModelBaseFragment<T extends IView, R extends AbstractV
1716
@Override
1817
public void onCreate(Bundle savedInstanceState) {
1918
super.onCreate(savedInstanceState);
20-
mViewModeHelper.onCreate(savedInstanceState, getViewModelClass(), getArguments());
19+
mViewModeHelper.onCreate(getActivity(), savedInstanceState, getViewModelClass(), getArguments());
2120
}
2221

2322
public abstract Class<R> getViewModelClass();
@@ -64,5 +63,4 @@ public void onDestroy() {
6463
public R getViewModel() {
6564
return mViewModeHelper.getViewModel();
6665
}
67-
6866
}

sample/src/main/java/eu/inloop/viewmodel/sample/activity/ViewPagerActivity.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
import android.support.v4.app.FragmentManager;
66
import android.support.v4.app.FragmentStatePagerAdapter;
77
import android.support.v4.view.ViewPager;
8-
import android.support.v7.app.AppCompatActivity;
98

9+
import eu.inloop.viewmodel.base.ViewModelBaseActivity;
1010
import eu.inloop.viewmodel.sample.R;
1111
import eu.inloop.viewmodel.sample.fragment.PagerFragment;
1212

13-
public class ViewPagerActivity extends AppCompatActivity {
13+
public class ViewPagerActivity extends ViewModelBaseActivity {
1414

1515
@Override
1616
protected void onCreate(Bundle savedInstanceState) {
@@ -20,7 +20,12 @@ protected void onCreate(Bundle savedInstanceState) {
2020
final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
2121
viewPager.setAdapter(new TestPagerAdapter(getSupportFragmentManager()));
2222
}
23-
23+
24+
@Override
25+
public Class getViewModelClass() {
26+
return null;
27+
}
28+
2429
private final static class TestPagerAdapter extends FragmentStatePagerAdapter {
2530
public TestPagerAdapter(FragmentManager fm) {
2631
super(fm);

0 commit comments

Comments
 (0)