Skip to content

Commit 0e329cb

Browse files
author
Daniel Novak
authored
Merge pull request #23 from stepansanda/databinding_support
Add databinding support
2 parents 0b8d399 + 6bc9490 commit 0e329cb

21 files changed

+418
-32
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ buildscript {
33
jcenter()
44
}
55
dependencies {
6-
classpath 'com.android.tools.build:gradle:2.2.0'
6+
classpath 'com.android.tools.build:gradle:2.2.2'
77
}
88
}
99

library/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ android {
2121
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
2222
}
2323
}
24+
25+
dataBinding {
26+
enabled = true;
27+
}
2428
}
2529

2630
dependencies {
Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
package eu.inloop.viewmodel;
22

3-
public interface IView {
3+
import android.support.annotation.Nullable;
4+
5+
import eu.inloop.viewmodel.binding.ViewModelBindingConfig;
46

7+
public interface IView {
8+
/**
9+
* This method is used for Data Binding to bind correct layout and variable atomatically
10+
* Can return null value in case that Data Binding is not used.
11+
*
12+
* @return defined ViewModelBinding Config for a specific screen.
13+
*/
14+
@Nullable
15+
ViewModelBindingConfig getViewModelBindingConfig();
516
}

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

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@
22

33
import android.app.Activity;
44
import android.content.Intent;
5+
import android.databinding.DataBindingUtil;
6+
import android.databinding.ViewDataBinding;
57
import android.os.Bundle;
68
import android.support.annotation.NonNull;
79
import android.support.annotation.Nullable;
810
import android.support.v4.app.Fragment;
911
import android.util.Log;
12+
import android.view.LayoutInflater;
1013

1114
import java.util.UUID;
1215

16+
import eu.inloop.viewmodel.binding.ViewModelBindingConfig;
17+
1318
public class ViewModelHelper<T extends IView, R extends AbstractViewModel<T>> {
1419

1520
@NonNull
@@ -21,18 +26,22 @@ public class ViewModelHelper<T extends IView, R extends AbstractViewModel<T>> {
2126
@Nullable
2227
private R mViewModel;
2328

29+
@Nullable
30+
private ViewDataBinding mBinding;
31+
2432
private boolean mModelRemoved;
2533
private boolean mOnSaveInstanceCalled;
2634

2735
/**
2836
* Call from {@link android.app.Activity#onCreate(android.os.Bundle)} or
2937
* {@link android.support.v4.app.Fragment#onCreate(android.os.Bundle)}
30-
* @param activity parent activity
38+
*
39+
* @param activity parent activity
3140
* @param savedInstanceState savedInstance state from {@link Activity#onCreate(Bundle)} or
3241
* {@link Fragment#onCreate(Bundle)}
33-
* @param viewModelClass the {@link Class} of your ViewModel
34-
* @param arguments pass {@link Fragment#getArguments()} or
35-
* {@link Activity#getIntent()}.{@link Intent#getExtras() getExtras()}
42+
* @param viewModelClass the {@link Class} of your ViewModel
43+
* @param arguments pass {@link Fragment#getArguments()} or
44+
* {@link Activity#getIntent()}.{@link Intent#getExtras() getExtras()}
3645
*/
3746
public void onCreate(@NonNull Activity activity,
3847
@Nullable Bundle savedInstanceState,
@@ -62,7 +71,7 @@ public void onCreate(@NonNull Activity activity,
6271
if (null == viewModelProvider) {
6372
throw new IllegalStateException("ViewModelProvider for activity " + activity + " was null."); //NON-NLS
6473
}
65-
74+
6675
final ViewModelProvider.ViewModelWrapper<T> viewModelWrapper = viewModelProvider.getViewModel(mScreenId, viewModelClass);
6776
//noinspection unchecked
6877
mViewModel = (R) viewModelWrapper.viewModel;
@@ -79,6 +88,7 @@ public void onCreate(@NonNull Activity activity,
7988
/**
8089
* Call from {@link android.support.v4.app.Fragment#onViewCreated(android.view.View, android.os.Bundle)}
8190
* or {@link android.app.Activity#onCreate(android.os.Bundle)}
91+
*
8292
* @param view view
8393
*/
8494
public void setView(@NonNull final T view) {
@@ -89,10 +99,44 @@ public void setView(@NonNull final T view) {
8999
mViewModel.onBindView(view);
90100
}
91101

102+
public void performBinding(@NonNull final IView bindingView) {
103+
// skip if already create
104+
if (mBinding != null) {
105+
return;
106+
}
107+
108+
// get ViewModelBinding config
109+
final ViewModelBindingConfig viewModelConfig = bindingView.getViewModelBindingConfig();
110+
// if fragment not providing ViewModelBindingConfig, do not perform binding operations
111+
if (viewModelConfig == null) {
112+
return;
113+
}
114+
115+
// perform Data Binding initialization
116+
final ViewDataBinding viewDataBinding;
117+
if (bindingView instanceof Activity) {
118+
viewDataBinding = DataBindingUtil.setContentView(((Activity) bindingView), viewModelConfig.getLayoutResource());
119+
} else if (bindingView instanceof Fragment) {
120+
viewDataBinding = DataBindingUtil.inflate(LayoutInflater.from(viewModelConfig.getContext()), viewModelConfig.getLayoutResource(), null, false);
121+
} else {
122+
throw new IllegalArgumentException("View must be an instance of Activity or Fragment (support-v4).");
123+
}
124+
125+
// bind all together
126+
if (!viewDataBinding.setVariable(viewModelConfig.getViewModelVariableName(), getViewModel())) {
127+
throw new IllegalArgumentException("Binding variable wasn't set successfully. Probably viewModelVariableName of your " +
128+
"ViewModelBindingConfig of " + bindingView.getClass().getSimpleName() + " doesn't match any variable in "
129+
+ viewDataBinding.getClass().getSimpleName());
130+
}
131+
132+
mBinding = viewDataBinding;
133+
}
134+
92135
/**
93136
* Use in case this model is associated with an {@link android.support.v4.app.Fragment}
94137
* Call from {@link android.support.v4.app.Fragment#onDestroyView()}. Use in case model is associated
95138
* with Fragment
139+
*
96140
* @param fragment fragment
97141
*/
98142
public void onDestroyView(@NonNull Fragment fragment) {
@@ -104,11 +148,13 @@ public void onDestroyView(@NonNull Fragment fragment) {
104148
if (fragment.getActivity() != null && fragment.getActivity().isFinishing()) {
105149
removeViewModel(fragment.getActivity());
106150
}
151+
mBinding = null;
107152
}
108153

109154
/**
110155
* Use in case this model is associated with an {@link android.support.v4.app.Fragment}
111156
* Call from {@link android.support.v4.app.Fragment#onDestroy()}
157+
*
112158
* @param fragment fragment
113159
*/
114160
public void onDestroy(@NonNull final Fragment fragment) {
@@ -126,11 +172,13 @@ public void onDestroy(@NonNull final Fragment fragment) {
126172
}
127173
removeViewModel(fragment.getActivity());
128174
}
175+
mBinding = null;
129176
}
130177

131178
/**
132179
* Use in case this model is associated with an {@link android.app.Activity}
133180
* Call from {@link android.app.Activity#onDestroy()}
181+
*
134182
* @param activity activity
135183
*/
136184
public void onDestroy(@NonNull final Activity activity) {
@@ -142,6 +190,7 @@ public void onDestroy(@NonNull final Activity activity) {
142190
if (activity.isFinishing()) {
143191
removeViewModel(activity);
144192
}
193+
mBinding = null;
145194
}
146195

147196
/**
@@ -172,6 +221,7 @@ public void onStart() {
172221
* Throws an {@link IllegalStateException} in case the ViewModel is null. This can happen
173222
* if you call this method too soon - before {@link Activity#onCreate(Bundle)} or {@link Fragment#onCreate(Bundle)}
174223
* or this {@link ViewModelHelper} is not properly setup.
224+
*
175225
* @return {@link R}
176226
*/
177227
@NonNull
@@ -186,6 +236,7 @@ public R getViewModel() {
186236
* Call from {@link android.app.Activity#onSaveInstanceState(android.os.Bundle)}
187237
* or {@link android.support.v4.app.Fragment#onSaveInstanceState(android.os.Bundle)}.
188238
* This allows the model to save its state.
239+
*
189240
* @param bundle bundle
190241
*/
191242
public void onSaveInstanceState(@NonNull Bundle bundle) {
@@ -196,6 +247,11 @@ public void onSaveInstanceState(@NonNull Bundle bundle) {
196247
}
197248
}
198249

250+
@Nullable
251+
public ViewDataBinding getBinding() {
252+
return mBinding;
253+
}
254+
199255
private void removeViewModel(@NonNull final Activity activity) {
200256
if (mViewModel != null && !mModelRemoved) {
201257
final ViewModelProvider viewModelProvider = getViewModelProvider(activity).getViewModelProvider();
@@ -205,6 +261,7 @@ private void removeViewModel(@NonNull final Activity activity) {
205261
viewModelProvider.remove(mScreenId);
206262
mViewModel.onDestroy();
207263
mModelRemoved = true;
264+
mBinding = null;
208265
}
209266
}
210267

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

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,61 +20,68 @@ public abstract class ViewModelBaseFragment<T extends IView, R extends AbstractV
2020
@Override
2121
public void onCreate(@Nullable final Bundle savedInstanceState) {
2222
super.onCreate(savedInstanceState);
23-
mViewModeHelper.onCreate(getActivity(), savedInstanceState, getViewModelClass(), getArguments());
24-
}
25-
26-
@Nullable
27-
public abstract Class<R> getViewModelClass();
28-
29-
/**
30-
* Call this after your view is ready - usually on the end of {@link Fragment#onViewCreated(View, Bundle)}
31-
* @param view view
32-
*/
33-
protected void setModelView(@NonNull final T view) {
34-
mViewModeHelper.setView(view);
23+
getViewModeHelper().onCreate(getActivity(), savedInstanceState, getViewModelClass(), getArguments());
3524
}
3625

3726
@CallSuper
3827
@Override
3928
public void onSaveInstanceState(@NonNull final Bundle outState) {
4029
super.onSaveInstanceState(outState);
41-
mViewModeHelper.onSaveInstanceState(outState);
30+
getViewModeHelper().onSaveInstanceState(outState);
4231
}
4332

4433
@CallSuper
4534
@Override
4635
public void onStart() {
4736
super.onStart();
48-
mViewModeHelper.onStart();
37+
getViewModeHelper().onStart();
4938
}
5039

5140
@CallSuper
5241
@Override
5342
public void onStop() {
5443
super.onStop();
55-
mViewModeHelper.onStop();
44+
getViewModeHelper().onStop();
5645
}
5746

5847
@CallSuper
5948
@Override
6049
public void onDestroyView() {
61-
mViewModeHelper.onDestroyView(this);
50+
getViewModeHelper().onDestroyView(this);
6251
super.onDestroyView();
6352
}
6453

6554
@CallSuper
6655
@Override
6756
public void onDestroy() {
68-
mViewModeHelper.onDestroy(this);
57+
getViewModeHelper().onDestroy(this);
6958
super.onDestroy();
7059
}
7160

61+
@Nullable
62+
public abstract Class<R> getViewModelClass();
63+
7264
/**
7365
* @see ViewModelHelper#getViewModel()
7466
*/
7567
@NonNull
7668
@SuppressWarnings("unused")
7769
public R getViewModel() {
78-
return mViewModeHelper.getViewModel();
70+
return getViewModeHelper().getViewModel();
71+
}
72+
73+
@NonNull
74+
public ViewModelHelper<T, R> getViewModeHelper() {
75+
return mViewModeHelper;
76+
}
77+
78+
/**
79+
* Call this after your view is ready - usually on the end of {@link
80+
* Fragment#onViewCreated(View, Bundle)}
81+
*
82+
* @param view view
83+
*/
84+
protected void setModelView(@NonNull final T view) {
85+
getViewModeHelper().setView(view);
7986
}
8087
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package eu.inloop.viewmodel.binding;
2+
3+
import android.databinding.ViewDataBinding;
4+
import android.os.Bundle;
5+
import android.support.annotation.Nullable;
6+
import android.view.LayoutInflater;
7+
import android.view.View;
8+
import android.view.ViewGroup;
9+
10+
import org.jetbrains.annotations.NotNull;
11+
12+
import eu.inloop.viewmodel.AbstractViewModel;
13+
import eu.inloop.viewmodel.IView;
14+
import eu.inloop.viewmodel.base.ViewModelBaseFragment;
15+
16+
public abstract class ViewModelBaseBindingFragment<T extends IView, R extends AbstractViewModel<T>, B extends ViewDataBinding>
17+
extends ViewModelBaseFragment<T, R>
18+
implements IView {
19+
20+
@Override
21+
public void onCreate(@Nullable Bundle savedInstanceState) {
22+
super.onCreate(savedInstanceState);
23+
getViewModeHelper().performBinding(this);
24+
}
25+
26+
@Nullable
27+
@Override
28+
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
29+
getViewModeHelper().performBinding(this);
30+
final ViewDataBinding binding = getViewModeHelper().getBinding();
31+
if (binding != null) {
32+
return binding.getRoot();
33+
} else {
34+
throw new IllegalStateException("Binding cannot be null. Perform binding before calling getBinding()");
35+
}
36+
}
37+
38+
@SuppressWarnings("unused")
39+
@NotNull
40+
public B getBinding() {
41+
try {
42+
return (B) getViewModeHelper().getBinding();
43+
} catch (ClassCastException ex) {
44+
throw new IllegalStateException("Method getViewModelBindingConfig() has to return same " +
45+
"ViewDataBinding type as it is set to base Fragment");
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)