From 7c95a1bec29a4357cf95aef62f1f97e2a9979600 Mon Sep 17 00:00:00 2001 From: Daniel Novak Date: Wed, 14 Sep 2016 10:07:07 +0200 Subject: [PATCH 01/43] Update dependencies --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 3 ++- library/build.gradle | 8 ++++---- sample/build.gradle | 12 ++++++------ 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/build.gradle b/build.gradle index c06351a..128f763 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.2.3' + classpath 'com.android.tools.build:gradle:2.1.3' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0bffd23..8fdb61d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Wed Sep 14 09:54:42 CEST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip diff --git a/library/build.gradle b/library/build.gradle index e438b14..9a6e438 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -2,12 +2,12 @@ apply plugin: 'com.android.library' apply plugin: 'maven' android { - compileSdkVersion 23 - buildToolsVersion '23.0.2' + compileSdkVersion 24 + buildToolsVersion '24.0.2' defaultConfig { minSdkVersion 15 - targetSdkVersion 23 + targetSdkVersion 24 versionCode 1 versionName VERSION_NAME } @@ -24,7 +24,7 @@ android { } dependencies { - compile 'com.android.support:appcompat-v7:23.1.1' + compile 'com.android.support:appcompat-v7:24.2.0' } task androidJavadocs(type: Javadoc) { diff --git a/sample/build.gradle b/sample/build.gradle index bd35607..38b5c90 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 23 - buildToolsVersion '23.0.2' + compileSdkVersion 24 + buildToolsVersion '24.0.2' defaultConfig { applicationId 'eu.inloop.viewmodel.sample' minSdkVersion 15 - targetSdkVersion 23 + targetSdkVersion 24 versionCode 1 versionName '1.0' } @@ -26,9 +26,9 @@ android { } dependencies { - compile 'com.android.support:appcompat-v7:23.1.1' - debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3' - releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3' + compile 'com.android.support:appcompat-v7:24.2.0' + debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4' + releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4' compile 'com.jakewharton:butterknife:5.1.2' compile project(':library') } From 956b8a0f6e890262bbbfa136143a6ffabf1c4853 Mon Sep 17 00:00:00 2001 From: Daniel Novak Date: Wed, 14 Sep 2016 10:10:06 +0200 Subject: [PATCH 02/43] Bump version to 1.0.1 --- CHANGELOG.md | 4 ++++ README.md | 2 +- gradle.properties | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5fa641..2b531b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.1(2016-9-14) + + - Updated dependencies (gradle, build tools, support library). + ## 1.0.0(2016-05-02) - We decided it's time for 1.0.0 release after a lot of use in production projects. diff --git a/README.md b/README.md index 601a92d..8d61abf 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ Download Grab via Gradle: ```groovy -compile 'eu.inloop:androidviewmodel:1.0.0' +compile 'eu.inloop:androidviewmodel:1.0.1' ``` Build and study sample application from source code or download from Google Play.
diff --git a/gradle.properties b/gradle.properties index a8aab98..9bedffc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,4 +17,4 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true -VERSION_NAME=1.0.0 \ No newline at end of file +VERSION_NAME=1.0.1 \ No newline at end of file From 74ba8ee6437f1cb27fad3e94f1dd946f08903efc Mon Sep 17 00:00:00 2001 From: Daniel Novak Date: Thu, 29 Sep 2016 09:00:26 +0200 Subject: [PATCH 03/43] Add annotations and cleanup code --- build.gradle | 2 +- library/build.gradle | 2 +- .../inloop/viewmodel/AbstractViewModel.java | 13 ++++---- .../inloop/viewmodel/IViewModelProvider.java | 3 ++ .../eu/inloop/viewmodel/ViewModelHelper.java | 30 +++++++++++++++---- .../inloop/viewmodel/ViewModelProvider.java | 30 +++++++++++-------- .../viewmodel/base/ViewModelBaseActivity.java | 8 +++++ .../base/ViewModelBaseEmptyActivity.java | 8 +++++ .../viewmodel/base/ViewModelBaseFragment.java | 8 +++++ sample/build.gradle | 2 +- .../viewmodel/sample/SampleApplication.java | 3 +- 11 files changed, 82 insertions(+), 27 deletions(-) diff --git a/build.gradle b/build.gradle index 128f763..03c181e 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.1.3' + classpath 'com.android.tools.build:gradle:2.2.0' } } diff --git a/library/build.gradle b/library/build.gradle index 9a6e438..2d7c20a 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -24,7 +24,7 @@ android { } dependencies { - compile 'com.android.support:appcompat-v7:24.2.0' + compile 'com.android.support:appcompat-v7:24.2.1' } task androidJavadocs(type: Javadoc) { diff --git a/library/src/main/java/eu/inloop/viewmodel/AbstractViewModel.java b/library/src/main/java/eu/inloop/viewmodel/AbstractViewModel.java index 78fee2f..96c1e6c 100644 --- a/library/src/main/java/eu/inloop/viewmodel/AbstractViewModel.java +++ b/library/src/main/java/eu/inloop/viewmodel/AbstractViewModel.java @@ -3,6 +3,7 @@ import android.app.Activity; import android.content.Intent; import android.os.Bundle; +import android.support.annotation.CallSuper; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; @@ -42,7 +43,7 @@ public String getUniqueIdentifier() { * only in case the system is killed due to low memory * and restored (and {@link #onSaveInstanceState(Bundle)} returned a non-null bundle. */ - @SuppressWarnings("EmptyMethod") + @SuppressWarnings({"EmptyMethod", "UnusedParameters"}) public void onCreate(@Nullable Bundle arguments, @Nullable Bundle savedInstanceState) { } @@ -50,8 +51,9 @@ public void onCreate(@Nullable Bundle arguments, @Nullable Bundle savedInstanceS /** * This method is an equivalent of {@link Fragment#onViewCreated(View, Bundle)} or {@link Activity#onCreate(Bundle)}. * At this point, the View is ready and you can initialise it. - * @param view + * @param view - View assigned to this ViewModel */ + @CallSuper public void onBindView(@NonNull T view) { mBindViewWasCalled = true; mView = view; @@ -62,21 +64,22 @@ public T getView() { return mView; } + @CallSuper public void clearView() { mView = null; } - @SuppressWarnings("EmptyMethod") + @SuppressWarnings({"EmptyMethod", "UnusedParameters"}) public void onSaveInstanceState(@NonNull final Bundle bundle) { } - @SuppressWarnings("EmptyMethod") + @SuppressWarnings({"EmptyMethod", "WeakerAccess"}) public void onStop() { } - @SuppressWarnings("EmptyMethod") + @SuppressWarnings({"EmptyMethod", "WeakerAccess"}) public void onStart() { if (mView == null && !mBindViewWasCalled) { Log.e("AndroidViewModel", this.getClass().getSimpleName() + " - no view associated. You probably did not call setModelView() in your Fragment or Activity"); diff --git a/library/src/main/java/eu/inloop/viewmodel/IViewModelProvider.java b/library/src/main/java/eu/inloop/viewmodel/IViewModelProvider.java index 62edc95..70e4555 100644 --- a/library/src/main/java/eu/inloop/viewmodel/IViewModelProvider.java +++ b/library/src/main/java/eu/inloop/viewmodel/IViewModelProvider.java @@ -1,5 +1,7 @@ package eu.inloop.viewmodel; +import android.support.annotation.Nullable; + /** * Your {@link android.app.Activity} must implement this interface if * any of the contained Fragments the {@link eu.inloop.viewmodel.ViewModelHelper} @@ -10,5 +12,6 @@ public interface IViewModelProvider { * See {@link eu.inloop.viewmodel.base.ViewModelBaseActivity} on how to implement. * @return the {@link ViewModelProvider}. */ + @Nullable ViewModelProvider getViewModelProvider(); } \ No newline at end of file diff --git a/library/src/main/java/eu/inloop/viewmodel/ViewModelHelper.java b/library/src/main/java/eu/inloop/viewmodel/ViewModelHelper.java index e1061e3..e8b9bfc 100644 --- a/library/src/main/java/eu/inloop/viewmodel/ViewModelHelper.java +++ b/library/src/main/java/eu/inloop/viewmodel/ViewModelHelper.java @@ -12,10 +12,15 @@ public class ViewModelHelper> { + @NonNull + private static final String STATE_STRING_SCREEN_IDENTIFIER = ViewModelHelper.class + ".state.string.identifier"; //NON-NLS + @Nullable private String mScreenId; + @Nullable private R mViewModel; + private boolean mModelRemoved; private boolean mOnSaveInstanceCalled; @@ -43,19 +48,29 @@ public void onCreate(@NonNull Activity activity, if (savedInstanceState == null) { mScreenId = UUID.randomUUID().toString(); } else { - mScreenId = savedInstanceState.getString("identifier"); + mScreenId = savedInstanceState.getString(STATE_STRING_SCREEN_IDENTIFIER); + if (null == mScreenId) { + throw new IllegalStateException("Bundle from onSaveInstanceState() didn't contain screen identifier. " + //NON-NLS + "Did you call ViewModelHelper.onSaveInstanceState?"); //NON-NLS + } + mOnSaveInstanceCalled = false; } // get model instance for this screen - final ViewModelProvider.ViewModelWrapper viewModelWrapper = getViewModelProvider(activity).getViewModelProvider().getViewModel(mScreenId, viewModelClass); + final ViewModelProvider viewModelProvider = getViewModelProvider(activity).getViewModelProvider(); + if (null == viewModelProvider) { + throw new IllegalStateException("ViewModelProvider for activity " + activity + " was null."); //NON-NLS + } + + final ViewModelProvider.ViewModelWrapper viewModelWrapper = viewModelProvider.getViewModel(mScreenId, viewModelClass); //noinspection unchecked mViewModel = (R) viewModelWrapper.viewModel; if (viewModelWrapper.wasCreated) { // detect that the system has killed the app - saved instance is not null, but the model was recreated if (BuildConfig.DEBUG && savedInstanceState != null) { - Log.d("model", "Fragment recreated by system - restoring viewmodel"); + Log.d("model", "Fragment recreated by system - restoring viewmodel"); //NON-NLS } mViewModel.onCreate(arguments, savedInstanceState); } @@ -174,7 +189,7 @@ public R getViewModel() { * @param bundle bundle */ public void onSaveInstanceState(@NonNull Bundle bundle) { - bundle.putString("identifier", mScreenId); + bundle.putString(STATE_STRING_SCREEN_IDENTIFIER, mScreenId); if (mViewModel != null) { mViewModel.onSaveInstanceState(bundle); mOnSaveInstanceCalled = true; @@ -183,12 +198,17 @@ public void onSaveInstanceState(@NonNull Bundle bundle) { private void removeViewModel(@NonNull final Activity activity) { if (mViewModel != null && !mModelRemoved) { - getViewModelProvider(activity).getViewModelProvider().remove(mScreenId); + final ViewModelProvider viewModelProvider = getViewModelProvider(activity).getViewModelProvider(); + if (null == viewModelProvider) { + throw new IllegalStateException("ViewModelProvider for activity " + activity + " was null."); //NON-NLS + } + viewModelProvider.remove(mScreenId); mViewModel.onDestroy(); mModelRemoved = true; } } + @NonNull private IViewModelProvider getViewModelProvider(@NonNull Activity activity) { if (!(activity instanceof IViewModelProvider)) { throw new IllegalStateException("Your activity must implement IViewModelProvider"); //NON-NLS diff --git a/library/src/main/java/eu/inloop/viewmodel/ViewModelProvider.java b/library/src/main/java/eu/inloop/viewmodel/ViewModelProvider.java index 4559190..c541de4 100644 --- a/library/src/main/java/eu/inloop/viewmodel/ViewModelProvider.java +++ b/library/src/main/java/eu/inloop/viewmodel/ViewModelProvider.java @@ -1,6 +1,7 @@ package eu.inloop.viewmodel; import android.app.Activity; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.v4.app.FragmentActivity; import java.util.HashMap; @@ -13,23 +14,26 @@ */ public class ViewModelProvider { + @NonNull private final HashMap> mViewModelCache; + @NonNull public static ViewModelProvider newInstance(@NonNull final FragmentActivity activity) { if (activity.getLastCustomNonConfigurationInstance() == null) { return new ViewModelProvider(); } else { - return (ViewModelProvider) activity.getLastCustomNonConfigurationInstance(); + return (ViewModelProvider) activity.getLastCustomNonConfigurationInstance(); } } @SuppressWarnings({"deprecation", "unused"}) + @NonNull @Deprecated public static ViewModelProvider newInstance(@NonNull final Activity activity) { if (activity.getLastNonConfigurationInstance() == null) { return new ViewModelProvider(); } else { - return (ViewModelProvider) activity.getLastNonConfigurationInstance(); + return (ViewModelProvider) activity.getLastNonConfigurationInstance(); } } @@ -37,7 +41,7 @@ private ViewModelProvider() { mViewModelCache = new HashMap<>(); } - public synchronized void remove(String modeIdentifier) { + public synchronized void remove(@Nullable String modeIdentifier) { mViewModelCache.remove(modeIdentifier); } @@ -47,8 +51,8 @@ public synchronized void removeAllViewModels() { @SuppressWarnings("unchecked") @NonNull - public synchronized ViewModelWrapper getViewModel(final String modelIdentifier, - final @NonNull Class> viewModelClass) { + public synchronized ViewModelWrapper getViewModel(@NonNull final String modelIdentifier, + @NonNull final Class> viewModelClass) { AbstractViewModel instance = (AbstractViewModel) mViewModelCache.get(modelIdentifier); if (instance != null) { return new ViewModelWrapper<>(instance, false); @@ -56,20 +60,20 @@ public synchronized ViewModelWrapper getViewModel(final Str try { instance = viewModelClass.newInstance(); - instance.setUniqueIdentifier(modelIdentifier); - mViewModelCache.put(modelIdentifier, instance); - return new ViewModelWrapper<>(instance, true); - } catch (Exception ex) { + } catch (final Exception ex) { throw new RuntimeException(ex); } + instance.setUniqueIdentifier(modelIdentifier); + mViewModelCache.put(modelIdentifier, instance); + return new ViewModelWrapper<>(instance, true); } - public static class ViewModelWrapper { + final static class ViewModelWrapper { @NonNull - public final AbstractViewModel viewModel; - public final boolean wasCreated; + final AbstractViewModel viewModel; + final boolean wasCreated; - private ViewModelWrapper(@NonNull AbstractViewModel mViewModel, boolean mWasCreated) { + private ViewModelWrapper(@NonNull AbstractViewModel mViewModel, final boolean mWasCreated) { this.viewModel = mViewModel; this.wasCreated = mWasCreated; } diff --git a/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseActivity.java b/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseActivity.java index cc86e98..bb59d88 100644 --- a/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseActivity.java +++ b/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseActivity.java @@ -1,6 +1,7 @@ package eu.inloop.viewmodel.base; import android.os.Bundle; +import android.support.annotation.CallSuper; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -10,8 +11,10 @@ public abstract class ViewModelBaseActivity> extends ViewModelBaseEmptyActivity implements IView { + @NonNull private final ViewModelHelper mViewModeHelper = new ViewModelHelper<>(); + @CallSuper @Override protected void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -27,26 +30,31 @@ public void setModelView(@NonNull final T view) { mViewModeHelper.setView(view); } + @Nullable public abstract Class getViewModelClass(); + @CallSuper @Override public void onSaveInstanceState(@NonNull final Bundle outState) { super.onSaveInstanceState(outState); mViewModeHelper.onSaveInstanceState(outState); } + @CallSuper @Override public void onStart() { super.onStart(); mViewModeHelper.onStart(); } + @CallSuper @Override public void onStop() { super.onStop(); mViewModeHelper.onStop(); } + @CallSuper @Override public void onDestroy() { mViewModeHelper.onDestroy(this); diff --git a/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseEmptyActivity.java b/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseEmptyActivity.java index 05395d7..35ebd20 100644 --- a/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseEmptyActivity.java +++ b/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseEmptyActivity.java @@ -1,6 +1,7 @@ package eu.inloop.viewmodel.base; import android.os.Bundle; +import android.support.annotation.CallSuper; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; @@ -14,8 +15,10 @@ */ public abstract class ViewModelBaseEmptyActivity extends AppCompatActivity implements IViewModelProvider { + @Nullable private ViewModelProvider mViewModelProvider; + @CallSuper @Override protected void onCreate(@Nullable final Bundle savedInstanceState) { //This code must be execute prior to super.onCreate() @@ -29,14 +32,19 @@ public Object onRetainCustomNonConfigurationInstance() { return mViewModelProvider; } + @CallSuper @Override public void onStop() { super.onStop(); if (isFinishing()) { + if (null == mViewModelProvider) { + throw new IllegalStateException("ViewModelProvider for activity " + this + " was null."); //NON-NLS + } mViewModelProvider.removeAllViewModels(); } } + @Nullable @Override public ViewModelProvider getViewModelProvider() { return mViewModelProvider; diff --git a/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseFragment.java b/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseFragment.java index a6ba060..485d070 100644 --- a/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseFragment.java +++ b/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseFragment.java @@ -1,6 +1,7 @@ package eu.inloop.viewmodel.base; import android.os.Bundle; +import android.support.annotation.CallSuper; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; @@ -12,8 +13,10 @@ public abstract class ViewModelBaseFragment> extends Fragment implements IView { + @NonNull private final ViewModelHelper mViewModeHelper = new ViewModelHelper<>(); + @CallSuper @Override public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -31,30 +34,35 @@ protected void setModelView(@NonNull final T view) { mViewModeHelper.setView(view); } + @CallSuper @Override public void onSaveInstanceState(@NonNull final Bundle outState) { super.onSaveInstanceState(outState); mViewModeHelper.onSaveInstanceState(outState); } + @CallSuper @Override public void onStart() { super.onStart(); mViewModeHelper.onStart(); } + @CallSuper @Override public void onStop() { super.onStop(); mViewModeHelper.onStop(); } + @CallSuper @Override public void onDestroyView() { mViewModeHelper.onDestroyView(this); super.onDestroyView(); } + @CallSuper @Override public void onDestroy() { mViewModeHelper.onDestroy(this); diff --git a/sample/build.gradle b/sample/build.gradle index 38b5c90..93c8615 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -26,7 +26,7 @@ android { } dependencies { - compile 'com.android.support:appcompat-v7:24.2.0' + compile 'com.android.support:appcompat-v7:24.2.1' debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4' compile 'com.jakewharton:butterknife:5.1.2' diff --git a/sample/src/main/java/eu/inloop/viewmodel/sample/SampleApplication.java b/sample/src/main/java/eu/inloop/viewmodel/sample/SampleApplication.java index 22452b3..0fe00cb 100644 --- a/sample/src/main/java/eu/inloop/viewmodel/sample/SampleApplication.java +++ b/sample/src/main/java/eu/inloop/viewmodel/sample/SampleApplication.java @@ -10,7 +10,8 @@ public class SampleApplication extends Application { private RefWatcher refWatcher; - @Override public void onCreate() { + @Override + public void onCreate() { super.onCreate(); refWatcher = LeakCanary.install(this); } From 6bc949085264ff758af78afee0ee0f16f359a5d7 Mon Sep 17 00:00:00 2001 From: Stepan Sanda Date: Mon, 21 Nov 2016 10:45:37 +0100 Subject: [PATCH 04/43] Add databinding support Base support for binding Add sample with simple binding Code cleaning Cleaning code - removing unnecessary helpers Add cast exception Add annotatoins, code cleaning and refactoring Remove implementation of getViewModelBindingConfig from ViewModelBaseFragment --- build.gradle | 2 +- library/build.gradle | 4 ++ .../main/java/eu/inloop/viewmodel/IView.java | 13 +++- .../eu/inloop/viewmodel/ViewModelHelper.java | 67 +++++++++++++++++-- .../viewmodel/base/ViewModelBaseFragment.java | 43 +++++++----- .../binding/ViewModelBaseBindingFragment.java | 48 +++++++++++++ .../binding/ViewModelBindingConfig.java | 59 ++++++++++++++++ .../layout/binding_variable_placeholder.xml | 12 ++++ sample/build.gradle | 4 ++ sample/src/main/AndroidManifest.xml | 6 +- .../activity/SampleBindingActivity.java | 29 ++++++++ .../sample/fragment/PagerFragment.java | 8 ++- .../fragment/SampleBindingFragment.java | 35 ++++++++++ .../sample/fragment/SampleBundleFragment.java | 8 ++- .../sample/fragment/UserListFragment.java | 20 +++++- .../viewmodel/SampleBindingViewModel.java | 33 +++++++++ .../sample/viewmodel/view/IPageView.java | 5 ++ .../viewmodel/view/ISampleBindingView.java | 10 +++ .../res/layout/activity_sample_binding.xml | 7 ++ .../res/layout/fragment_sample_binding.xml | 29 ++++++++ .../src/main/res/layout/fragment_userlist.xml | 8 +++ 21 files changed, 418 insertions(+), 32 deletions(-) create mode 100644 library/src/main/java/eu/inloop/viewmodel/binding/ViewModelBaseBindingFragment.java create mode 100644 library/src/main/java/eu/inloop/viewmodel/binding/ViewModelBindingConfig.java create mode 100644 library/src/main/res/layout/binding_variable_placeholder.xml create mode 100644 sample/src/main/java/eu/inloop/viewmodel/sample/activity/SampleBindingActivity.java create mode 100644 sample/src/main/java/eu/inloop/viewmodel/sample/fragment/SampleBindingFragment.java create mode 100644 sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/SampleBindingViewModel.java create mode 100644 sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/view/ISampleBindingView.java create mode 100644 sample/src/main/res/layout/activity_sample_binding.xml create mode 100644 sample/src/main/res/layout/fragment_sample_binding.xml diff --git a/build.gradle b/build.gradle index 03c181e..bbdda21 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.0' + classpath 'com.android.tools.build:gradle:2.2.2' } } diff --git a/library/build.gradle b/library/build.gradle index 2d7c20a..30344aa 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -21,6 +21,10 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + + dataBinding { + enabled = true; + } } dependencies { diff --git a/library/src/main/java/eu/inloop/viewmodel/IView.java b/library/src/main/java/eu/inloop/viewmodel/IView.java index 300c4b3..4a06026 100644 --- a/library/src/main/java/eu/inloop/viewmodel/IView.java +++ b/library/src/main/java/eu/inloop/viewmodel/IView.java @@ -1,5 +1,16 @@ package eu.inloop.viewmodel; -public interface IView { +import android.support.annotation.Nullable; + +import eu.inloop.viewmodel.binding.ViewModelBindingConfig; +public interface IView { + /** + * This method is used for Data Binding to bind correct layout and variable atomatically + * Can return null value in case that Data Binding is not used. + * + * @return defined ViewModelBinding Config for a specific screen. + */ + @Nullable + ViewModelBindingConfig getViewModelBindingConfig(); } diff --git a/library/src/main/java/eu/inloop/viewmodel/ViewModelHelper.java b/library/src/main/java/eu/inloop/viewmodel/ViewModelHelper.java index e8b9bfc..322cc88 100644 --- a/library/src/main/java/eu/inloop/viewmodel/ViewModelHelper.java +++ b/library/src/main/java/eu/inloop/viewmodel/ViewModelHelper.java @@ -2,14 +2,19 @@ import android.app.Activity; import android.content.Intent; +import android.databinding.DataBindingUtil; +import android.databinding.ViewDataBinding; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.util.Log; +import android.view.LayoutInflater; import java.util.UUID; +import eu.inloop.viewmodel.binding.ViewModelBindingConfig; + public class ViewModelHelper> { @NonNull @@ -21,18 +26,22 @@ public class ViewModelHelper> { @Nullable private R mViewModel; + @Nullable + private ViewDataBinding mBinding; + private boolean mModelRemoved; private boolean mOnSaveInstanceCalled; /** * Call from {@link android.app.Activity#onCreate(android.os.Bundle)} or * {@link android.support.v4.app.Fragment#onCreate(android.os.Bundle)} - * @param activity parent activity + * + * @param activity parent activity * @param savedInstanceState savedInstance state from {@link Activity#onCreate(Bundle)} or * {@link Fragment#onCreate(Bundle)} - * @param viewModelClass the {@link Class} of your ViewModel - * @param arguments pass {@link Fragment#getArguments()} or - * {@link Activity#getIntent()}.{@link Intent#getExtras() getExtras()} + * @param viewModelClass the {@link Class} of your ViewModel + * @param arguments pass {@link Fragment#getArguments()} or + * {@link Activity#getIntent()}.{@link Intent#getExtras() getExtras()} */ public void onCreate(@NonNull Activity activity, @Nullable Bundle savedInstanceState, @@ -62,7 +71,7 @@ public void onCreate(@NonNull Activity activity, if (null == viewModelProvider) { throw new IllegalStateException("ViewModelProvider for activity " + activity + " was null."); //NON-NLS } - + final ViewModelProvider.ViewModelWrapper viewModelWrapper = viewModelProvider.getViewModel(mScreenId, viewModelClass); //noinspection unchecked mViewModel = (R) viewModelWrapper.viewModel; @@ -79,6 +88,7 @@ public void onCreate(@NonNull Activity activity, /** * Call from {@link android.support.v4.app.Fragment#onViewCreated(android.view.View, android.os.Bundle)} * or {@link android.app.Activity#onCreate(android.os.Bundle)} + * * @param view view */ public void setView(@NonNull final T view) { @@ -89,10 +99,44 @@ public void setView(@NonNull final T view) { mViewModel.onBindView(view); } + public void performBinding(@NonNull final IView bindingView) { + // skip if already create + if (mBinding != null) { + return; + } + + // get ViewModelBinding config + final ViewModelBindingConfig viewModelConfig = bindingView.getViewModelBindingConfig(); + // if fragment not providing ViewModelBindingConfig, do not perform binding operations + if (viewModelConfig == null) { + return; + } + + // perform Data Binding initialization + final ViewDataBinding viewDataBinding; + if (bindingView instanceof Activity) { + viewDataBinding = DataBindingUtil.setContentView(((Activity) bindingView), viewModelConfig.getLayoutResource()); + } else if (bindingView instanceof Fragment) { + viewDataBinding = DataBindingUtil.inflate(LayoutInflater.from(viewModelConfig.getContext()), viewModelConfig.getLayoutResource(), null, false); + } else { + throw new IllegalArgumentException("View must be an instance of Activity or Fragment (support-v4)."); + } + + // bind all together + if (!viewDataBinding.setVariable(viewModelConfig.getViewModelVariableName(), getViewModel())) { + throw new IllegalArgumentException("Binding variable wasn't set successfully. Probably viewModelVariableName of your " + + "ViewModelBindingConfig of " + bindingView.getClass().getSimpleName() + " doesn't match any variable in " + + viewDataBinding.getClass().getSimpleName()); + } + + mBinding = viewDataBinding; + } + /** * Use in case this model is associated with an {@link android.support.v4.app.Fragment} * Call from {@link android.support.v4.app.Fragment#onDestroyView()}. Use in case model is associated * with Fragment + * * @param fragment fragment */ public void onDestroyView(@NonNull Fragment fragment) { @@ -104,11 +148,13 @@ public void onDestroyView(@NonNull Fragment fragment) { if (fragment.getActivity() != null && fragment.getActivity().isFinishing()) { removeViewModel(fragment.getActivity()); } + mBinding = null; } /** * Use in case this model is associated with an {@link android.support.v4.app.Fragment} * Call from {@link android.support.v4.app.Fragment#onDestroy()} + * * @param fragment fragment */ public void onDestroy(@NonNull final Fragment fragment) { @@ -126,11 +172,13 @@ public void onDestroy(@NonNull final Fragment fragment) { } removeViewModel(fragment.getActivity()); } + mBinding = null; } /** * Use in case this model is associated with an {@link android.app.Activity} * Call from {@link android.app.Activity#onDestroy()} + * * @param activity activity */ public void onDestroy(@NonNull final Activity activity) { @@ -142,6 +190,7 @@ public void onDestroy(@NonNull final Activity activity) { if (activity.isFinishing()) { removeViewModel(activity); } + mBinding = null; } /** @@ -172,6 +221,7 @@ public void onStart() { * Throws an {@link IllegalStateException} in case the ViewModel is null. This can happen * if you call this method too soon - before {@link Activity#onCreate(Bundle)} or {@link Fragment#onCreate(Bundle)} * or this {@link ViewModelHelper} is not properly setup. + * * @return {@link R} */ @NonNull @@ -186,6 +236,7 @@ public R getViewModel() { * Call from {@link android.app.Activity#onSaveInstanceState(android.os.Bundle)} * or {@link android.support.v4.app.Fragment#onSaveInstanceState(android.os.Bundle)}. * This allows the model to save its state. + * * @param bundle bundle */ public void onSaveInstanceState(@NonNull Bundle bundle) { @@ -196,6 +247,11 @@ public void onSaveInstanceState(@NonNull Bundle bundle) { } } + @Nullable + public ViewDataBinding getBinding() { + return mBinding; + } + private void removeViewModel(@NonNull final Activity activity) { if (mViewModel != null && !mModelRemoved) { final ViewModelProvider viewModelProvider = getViewModelProvider(activity).getViewModelProvider(); @@ -205,6 +261,7 @@ private void removeViewModel(@NonNull final Activity activity) { viewModelProvider.remove(mScreenId); mViewModel.onDestroy(); mModelRemoved = true; + mBinding = null; } } diff --git a/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseFragment.java b/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseFragment.java index 485d070..354b7ed 100644 --- a/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseFragment.java +++ b/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseFragment.java @@ -20,61 +20,68 @@ public abstract class ViewModelBaseFragment getViewModelClass(); - - /** - * Call this after your view is ready - usually on the end of {@link Fragment#onViewCreated(View, Bundle)} - * @param view view - */ - protected void setModelView(@NonNull final T view) { - mViewModeHelper.setView(view); + getViewModeHelper().onCreate(getActivity(), savedInstanceState, getViewModelClass(), getArguments()); } @CallSuper @Override public void onSaveInstanceState(@NonNull final Bundle outState) { super.onSaveInstanceState(outState); - mViewModeHelper.onSaveInstanceState(outState); + getViewModeHelper().onSaveInstanceState(outState); } @CallSuper @Override public void onStart() { super.onStart(); - mViewModeHelper.onStart(); + getViewModeHelper().onStart(); } @CallSuper @Override public void onStop() { super.onStop(); - mViewModeHelper.onStop(); + getViewModeHelper().onStop(); } @CallSuper @Override public void onDestroyView() { - mViewModeHelper.onDestroyView(this); + getViewModeHelper().onDestroyView(this); super.onDestroyView(); } @CallSuper @Override public void onDestroy() { - mViewModeHelper.onDestroy(this); + getViewModeHelper().onDestroy(this); super.onDestroy(); } + @Nullable + public abstract Class getViewModelClass(); + /** * @see ViewModelHelper#getViewModel() */ @NonNull @SuppressWarnings("unused") public R getViewModel() { - return mViewModeHelper.getViewModel(); + return getViewModeHelper().getViewModel(); + } + + @NonNull + public ViewModelHelper getViewModeHelper() { + return mViewModeHelper; + } + + /** + * Call this after your view is ready - usually on the end of {@link + * Fragment#onViewCreated(View, Bundle)} + * + * @param view view + */ + protected void setModelView(@NonNull final T view) { + getViewModeHelper().setView(view); } } diff --git a/library/src/main/java/eu/inloop/viewmodel/binding/ViewModelBaseBindingFragment.java b/library/src/main/java/eu/inloop/viewmodel/binding/ViewModelBaseBindingFragment.java new file mode 100644 index 0000000..7b8fca8 --- /dev/null +++ b/library/src/main/java/eu/inloop/viewmodel/binding/ViewModelBaseBindingFragment.java @@ -0,0 +1,48 @@ +package eu.inloop.viewmodel.binding; + +import android.databinding.ViewDataBinding; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.jetbrains.annotations.NotNull; + +import eu.inloop.viewmodel.AbstractViewModel; +import eu.inloop.viewmodel.IView; +import eu.inloop.viewmodel.base.ViewModelBaseFragment; + +public abstract class ViewModelBaseBindingFragment, B extends ViewDataBinding> + extends ViewModelBaseFragment + implements IView { + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getViewModeHelper().performBinding(this); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + getViewModeHelper().performBinding(this); + final ViewDataBinding binding = getViewModeHelper().getBinding(); + if (binding != null) { + return binding.getRoot(); + } else { + throw new IllegalStateException("Binding cannot be null. Perform binding before calling getBinding()"); + } + } + + @SuppressWarnings("unused") + @NotNull + public B getBinding() { + try { + return (B) getViewModeHelper().getBinding(); + } catch (ClassCastException ex) { + throw new IllegalStateException("Method getViewModelBindingConfig() has to return same " + + "ViewDataBinding type as it is set to base Fragment"); + } + } +} diff --git a/library/src/main/java/eu/inloop/viewmodel/binding/ViewModelBindingConfig.java b/library/src/main/java/eu/inloop/viewmodel/binding/ViewModelBindingConfig.java new file mode 100644 index 0000000..d008c47 --- /dev/null +++ b/library/src/main/java/eu/inloop/viewmodel/binding/ViewModelBindingConfig.java @@ -0,0 +1,59 @@ +package eu.inloop.viewmodel.binding; + +import android.content.Context; +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; + +import eu.inloop.viewmodel.BR; + +/** + * Use this to define a ViewModelBinding Config for a specific screen. + *

+ * Config contains layout resource ID, Context, ViewModel binding variable name + */ +public class ViewModelBindingConfig { + + @LayoutRes + private final int mLayoutResource; + private final int mViewModelVariableName; + @NonNull + private final Context mContext; + + /** + * Create a ViewModelBinding Config object for an Activity/Fragment + * This constructor should be used if the binding variable is named differently + * + * @param layoutResource Layout resource ID + * @param viewModelVariableName Data Binding variable name for injecting the ViewModel - use + * generated id (e.g. BR.mViewModel) + */ + public ViewModelBindingConfig(@LayoutRes int layoutResource, int viewModelVariableName, @NonNull Context context) { + mLayoutResource = layoutResource; + mViewModelVariableName = viewModelVariableName; + mContext = context; + } + + /** + * Create a ViewModelBinding Config object for an Activity/Fragment + * Use this constructor if the binding variable is named viewModel + * + * @param layoutResource Layout resource ID + */ + public ViewModelBindingConfig(@LayoutRes int layoutResource, @NonNull Context context) { + this(layoutResource, BR.viewModel, context); + } + + @LayoutRes + public int getLayoutResource() { + return mLayoutResource; + } + + public int getViewModelVariableName() { + return mViewModelVariableName; + } + + @NonNull + public Context getContext() { + return mContext; + } +} diff --git a/library/src/main/res/layout/binding_variable_placeholder.xml b/library/src/main/res/layout/binding_variable_placeholder.xml new file mode 100644 index 0000000..32835f4 --- /dev/null +++ b/library/src/main/res/layout/binding_variable_placeholder.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/sample/build.gradle b/sample/build.gradle index 93c8615..b95bfe8 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -23,6 +23,10 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + + dataBinding { + enabled = true; + } } dependencies { diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 66c08c6..3e803de 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -5,19 +5,19 @@ + android:label="@string/app_name"> - + + diff --git a/sample/src/main/java/eu/inloop/viewmodel/sample/activity/SampleBindingActivity.java b/sample/src/main/java/eu/inloop/viewmodel/sample/activity/SampleBindingActivity.java new file mode 100644 index 0000000..9ea4528 --- /dev/null +++ b/sample/src/main/java/eu/inloop/viewmodel/sample/activity/SampleBindingActivity.java @@ -0,0 +1,29 @@ +package eu.inloop.viewmodel.sample.activity; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import butterknife.ButterKnife; +import eu.inloop.viewmodel.base.ViewModelBaseEmptyActivity; +import eu.inloop.viewmodel.sample.R; +import eu.inloop.viewmodel.sample.fragment.SampleBindingFragment; + +public class SampleBindingActivity extends ViewModelBaseEmptyActivity { + + public static Intent newIntent(Context context) { + Intent intent = new Intent(context, SampleBindingActivity.class); + return intent; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + ButterKnife.inject(this); + + if (savedInstanceState == null) { + getSupportFragmentManager().beginTransaction().replace(R.id.root_content, new SampleBindingFragment(), "sample-binding-fragment").commit(); + } + } +} diff --git a/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/PagerFragment.java b/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/PagerFragment.java index 5168466..a866508 100644 --- a/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/PagerFragment.java +++ b/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/PagerFragment.java @@ -2,7 +2,6 @@ import android.os.Bundle; import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -11,6 +10,7 @@ import com.squareup.leakcanary.RefWatcher; import eu.inloop.viewmodel.base.ViewModelBaseFragment; +import eu.inloop.viewmodel.binding.ViewModelBindingConfig; import eu.inloop.viewmodel.sample.R; import eu.inloop.viewmodel.sample.SampleApplication; import eu.inloop.viewmodel.sample.viewmodel.PageModel; @@ -51,4 +51,10 @@ public void onDestroy() { RefWatcher refWatcher = SampleApplication.getRefWatcher(getActivity()); refWatcher.watch(this); } + + @Nullable + @Override + public ViewModelBindingConfig getViewModelBindingConfig() { + return null; + } } diff --git a/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/SampleBindingFragment.java b/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/SampleBindingFragment.java new file mode 100644 index 0000000..6db4912 --- /dev/null +++ b/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/SampleBindingFragment.java @@ -0,0 +1,35 @@ +package eu.inloop.viewmodel.sample.fragment; + +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; + +import eu.inloop.viewmodel.binding.ViewModelBaseBindingFragment; +import eu.inloop.viewmodel.binding.ViewModelBindingConfig; +import eu.inloop.viewmodel.sample.R; +import eu.inloop.viewmodel.sample.databinding.FragmentSampleBindingBinding; +import eu.inloop.viewmodel.sample.viewmodel.SampleBindingViewModel; +import eu.inloop.viewmodel.sample.viewmodel.view.ISampleBindingView; + +/** + * A simple {@link Fragment} subclass. + */ +public class SampleBindingFragment + extends ViewModelBaseBindingFragment + implements ISampleBindingView { + + public SampleBindingFragment() { + // Required empty public constructor + } + + @Override + public ViewModelBindingConfig getViewModelBindingConfig() { + return new ViewModelBindingConfig(R.layout.fragment_sample_binding, getActivity()); + } + + @Nullable + @Override + public Class getViewModelClass() { + return SampleBindingViewModel.class; + } + +} diff --git a/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/SampleBundleFragment.java b/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/SampleBundleFragment.java index c3d6378..2b53568 100644 --- a/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/SampleBundleFragment.java +++ b/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/SampleBundleFragment.java @@ -2,7 +2,6 @@ import android.os.Bundle; import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -10,6 +9,7 @@ import butterknife.ButterKnife; import eu.inloop.viewmodel.IView; import eu.inloop.viewmodel.base.ViewModelBaseFragment; +import eu.inloop.viewmodel.binding.ViewModelBindingConfig; import eu.inloop.viewmodel.sample.R; import eu.inloop.viewmodel.sample.viewmodel.SampleArgumentViewModel; @@ -41,4 +41,10 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { public Class getViewModelClass() { return SampleArgumentViewModel.class; } + + @Nullable + @Override + public ViewModelBindingConfig getViewModelBindingConfig() { + return null; + } } diff --git a/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/UserListFragment.java b/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/UserListFragment.java index 7c3d759..1187c03 100644 --- a/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/UserListFragment.java +++ b/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/UserListFragment.java @@ -8,6 +8,7 @@ import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.Button; import android.widget.ListView; import android.widget.TextView; @@ -19,8 +20,10 @@ import butterknife.ButterKnife; import butterknife.InjectView; import eu.inloop.viewmodel.base.ViewModelBaseFragment; +import eu.inloop.viewmodel.binding.ViewModelBindingConfig; import eu.inloop.viewmodel.sample.R; import eu.inloop.viewmodel.sample.SampleApplication; +import eu.inloop.viewmodel.sample.activity.SampleBindingActivity; import eu.inloop.viewmodel.sample.activity.ViewPagerActivity; import eu.inloop.viewmodel.sample.viewmodel.UserListViewModel; import eu.inloop.viewmodel.sample.viewmodel.view.IUserListView; @@ -33,6 +36,8 @@ public class UserListFragment extends ViewModelBaseFragment mAdapter; @@ -47,7 +52,6 @@ public Class getViewModelClass() { return UserListViewModel.class; } - @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.fragment_userlist, container, false); @@ -74,6 +78,12 @@ public void onClick(View view) { } }); mListview.addHeaderView(headerView, null, false); + mOpenBindingFragment.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(SampleBindingActivity.newIntent(getActivity())); + } + }); return view; } @@ -98,7 +108,7 @@ public void showUsers(List users) { mAdapter.setNotifyOnChange(true); mAdapter.notifyDataSetChanged(); } - + @Override public void showLoading(float progress) { mProgressView.setVisibility(View.VISIBLE); @@ -118,4 +128,10 @@ public void onDestroy() { RefWatcher refWatcher = SampleApplication.getRefWatcher(getActivity()); refWatcher.watch(this); } + + @Nullable + @Override + public ViewModelBindingConfig getViewModelBindingConfig() { + return null; + } } diff --git a/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/SampleBindingViewModel.java b/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/SampleBindingViewModel.java new file mode 100644 index 0000000..40a74e5 --- /dev/null +++ b/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/SampleBindingViewModel.java @@ -0,0 +1,33 @@ +package eu.inloop.viewmodel.sample.viewmodel; + +import android.databinding.ObservableField; +import android.os.Bundle; +import android.support.annotation.Nullable; + +import eu.inloop.viewmodel.AbstractViewModel; +import eu.inloop.viewmodel.sample.viewmodel.view.ISampleBindingView; + +/** + * Created by stepansanda on 21/11/2016. + */ + +public class SampleBindingViewModel extends AbstractViewModel { + + public final ObservableField text = new ObservableField<>(); + private int mButtonClickedCounter = 0; + + @Override + public void onCreate(@Nullable Bundle arguments, @Nullable Bundle savedInstanceState) { + super.onCreate(arguments, savedInstanceState); + setButtonClickedText(); + } + + public void onButtonClick() { + mButtonClickedCounter++; + setButtonClickedText(); + } + + private void setButtonClickedText() { + text.set("Button Clicked: " + mButtonClickedCounter + " times"); + } +} diff --git a/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/view/IPageView.java b/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/view/IPageView.java index fab1625..ab4112b 100644 --- a/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/view/IPageView.java +++ b/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/view/IPageView.java @@ -1,6 +1,11 @@ package eu.inloop.viewmodel.sample.viewmodel.view; import eu.inloop.viewmodel.IView; +import eu.inloop.viewmodel.binding.ViewModelBindingConfig; public class IPageView implements IView { + @Override + public ViewModelBindingConfig getViewModelBindingConfig() { + return null; + } } diff --git a/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/view/ISampleBindingView.java b/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/view/ISampleBindingView.java new file mode 100644 index 0000000..983c325 --- /dev/null +++ b/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/view/ISampleBindingView.java @@ -0,0 +1,10 @@ +package eu.inloop.viewmodel.sample.viewmodel.view; + +import eu.inloop.viewmodel.IView; + +/** + * Created by stepansanda on 21/11/2016. + */ + +public interface ISampleBindingView extends IView { +} diff --git a/sample/src/main/res/layout/activity_sample_binding.xml b/sample/src/main/res/layout/activity_sample_binding.xml new file mode 100644 index 0000000..81d46df --- /dev/null +++ b/sample/src/main/res/layout/activity_sample_binding.xml @@ -0,0 +1,7 @@ + diff --git a/sample/src/main/res/layout/fragment_sample_binding.xml b/sample/src/main/res/layout/fragment_sample_binding.xml new file mode 100644 index 0000000..05b0828 --- /dev/null +++ b/sample/src/main/res/layout/fragment_sample_binding.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + +