diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2b531b5..e30c163 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,54 @@
+## 1.4.0(2019-02-13)
+
+- Migrate to AndroidX
+
+## 1.3.5(2018-03-07)
+
+- Updated dependencies (Support library, build tools, Gradle).
+
+## 1.3.4(2017-11-02)
+
+- Update Gradle plugin. Fix Nullable annotation in getBinding().
+
+## 1.3.3(2017-08-21)
+
+- Fix issue where viewmodels with generic types would not work correctly.
+
+## 1.3.2(2017-08-21)
+
+- Updated dependencies (Support library, build tools, gradle)
+
+## 1.3.1(2017-02-20)
+
+- Critical issue fixed that was introduced two days ago in 1.3.0 - please update to 1.3.1 (issue is related to the new getViewOptional() method).
+
+## 1.3.0(2017-02-18)
+
+- Added ``getViewOptional()`` method which is guaranteed to be non-null. It will return a dummy implemenation in case the View is not null.
+- Removed the need to override ```getViewModelClass```, the ViewModel class is now automatically extracted from the ViewModel class definition.
+
+## 1.2.3(2017-01-4)
+
+- Fix ProGuard settings.
+
+## 1.2.2(2017-01-02)
+
+- Remove wrong jetbrains annotations import.
+
+## 1.2.1(2016-12-08)
+
+- Added default (null) implementation of ```getViewModelConfig()``` to the ```ViewModelBaseActivity``` so you don't need to implement it for your Activities.
+
+## 1.2.0(2016-11-24)
+
+- Added better support for FragmentStatePagerAdapter by adding [ViewModelStatePagerAdapter.java](library/src/main/java/eu/inloop/viewmodel/support/ViewModelStatePagerAdapter.java).
+- Breaking change: Added ```removeViewModel()``` to [IView](library/src/main/java/eu/inloop/viewmodel/IView.java). You don't need to make any changes if you are using the default ViewModelBaseFragment. Otherwise you need to implement this method and return null in case you don't need data binding.
+
+## 1.1.0(2016-11-24)
+
+- Added support for data binding
+- Breaking change: Added ```getViewModelConfig()``` to [IView](library/src/main/java/eu/inloop/viewmodel/IView.java). You don't need to make any changes if you are using the default ViewModelBaseFragment. Otherwise you need to implement this method and return null in case you don't need data binding.
+
## 1.0.1(2016-9-14)
- Updated dependencies (gradle, build tools, support library).
diff --git a/README.md b/README.md
index 8ade53b..d7dee4a 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,12 @@
AndroidViewModel
================
+Important notice: Deprecated
+--------
+This library served it's purpose for over 3 years. We believe that Google's Android [Architecture Components](https://developer.android.com/topic/libraries/architecture/index.html) are the preferred setup now for new projects.
+[INLOOPX](http://www.inloopx.com) is dedicated to continue maintaining this library (no deadline on support end). So rest assured that your existing projects don't need be migrated from AndroidViewModel because of this deprecation. We are only stopping new feature development and don't recommend using it for new projects.
+
+
Separating data and state handling from Fragments or Activities without lots of boilerplate-code. Reducing them to simple dumb views.
Basic idea behind this library.
@@ -15,10 +21,10 @@ How to implement
1. Create an interface for your View by extending [IView](library/src/main/java/eu/inloop/viewmodel/IView.java). We will call it IUserListView for this example.
```java
-
- public interface IUserListView extends IView {
- public void showUsers(List users);
- }
+ public interface IUserListView extends IView {
+ public void showUsers(List users);
+ }
+
```
2. Create your ViewModel class by extending [AbstractViewModel](library/src/main/java/eu/inloop/viewmodel/AbstractViewModel.java). For example:
@@ -27,17 +33,12 @@ How to implement
....
}
```
-3. Each Fragment or Activity that you would like to associate with a ViewModel will need either to extend [ViewModelActivityBase](library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseActivity.java)/[ViewModelBaseFragment](library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseFragment.java) or copy the implementation from these classes to your base activity/fragment class (in case you can't inherit directly). Override ```getViewModelClass()``` to return the corresponding ViewModel class. For example:
+3. Each Fragment or Activity that you would like to associate with a ViewModel will need either to extend [ViewModelActivityBase](library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseActivity.java)/[ViewModelBaseFragment](library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseFragment.java) or copy the implementation from these classes to your base activity/fragment class (in case you can't inherit directly). For example:
```java
public class UserListFragment extends ViewModelBaseFragment
implements IUserListView {
- @Override
- public Class getViewModelClass() {
- return UserListViewModel.class;
- }
-
}
```
@@ -63,6 +64,13 @@ You can forward user interaction from the View into the ViewModel simply by call
The same goes for the opposite direction, when your asynchronous operation in the ViewModel finished and you would like to forward data to the View to show a list for example:
+ ```java
+ getViewOptional().showUsers(userList);
+ ```
+
+The ```getViewOptional()``` method will never return null. It will return a dummy implementation in case the View is null at the moment (e.g. Fragment already destroyed, or between orientation change).
+You can also check if the View is not null in case you need to:
+
```java
if (getView() != null) {
getView().showUsers(userList);
@@ -76,6 +84,7 @@ Your Fragment argument Bundle and Activity intent Bundle is forwarded to the Vie
long userId = arguments.getInt("user_id", -1);
}
```
+
Data binding support
--------
@@ -84,12 +93,20 @@ Data binding is supported - extend [ViewModelBaseBindingFragment.java](library/s
``` java
@Override
public ViewModelBindingConfig getViewModelBindingConfig() {
- return new ViewModelBindingConfig(R.layout.fragment_sample_binding, getActivity());
+ return new ViewModelBindingConfig(R.layout.fragment_sample_binding, requireActivity());
}
```
That's it. You can then directly use ObservableField in your ViewModels. See [example](sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/SampleBindingViewModel.java).
+Special handling for FragmentStatePagerAdapter
+--------
+The Android implementation of [FragmentStatePagerAdapter](https://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html) is removing Fragments and storing their state. This is in contrast with [FragmentPagerAdapter](https://developer.android.com/reference/android/support/v4/app/FragmentPagerAdapter.html) where the Fragments are just detached but not removed.
+We should be also removing ViewModels and storing their state to be consistent with this behaviour.
+
+Use [ViewModelStatePagerAdapter](library/src/main/java/eu/inloop/viewmodel/support/ViewModelStatePagerAdapter.java) instead of the default FragmentStatePagerAdapter. This class is only overriding the ```destroyItem()``` method and making sure that ViewModel is removed. The state is stored/restored automatically.
+You can also use the standard FragmentStatePagerAdapter - in that case ViewModels will be kept in memory and removed only when you leave the screen (Activity finished or Fragment removed).
+
How does it work?
--------
@@ -101,5 +118,26 @@ Download
--------
```groovy
-compile 'eu.inloop:androidviewmodel:1.0.1'
+compile 'eu.inloop:androidviewmodel:1.4.0'
+```
+
+## Android Studio Template
+For faster creating new screens, you can use [Android Studio Template](/template/AVM_Inloop)
+
+
+
+### Install template
+#### Manually:
+Copy the template folder to Android Studio templates folder (`/Applications/Android Studio.app/Contents/plugins/android/lib/templates/others` on Mac)
+#### Automatically:
+Run the following command to download and install the template automatically (Mac only)
+```
+curl -o androidviewmodel.zip -Lk https://github.com/inloop/AndroidViewModel/archive/master.zip && unzip androidviewmodel.zip && cp -af AndroidViewModel-master/template/AVM_Inloop/. "/Applications/Android Studio.app/Contents/plugins/android/lib/templates/other/AVM_Inloop" && rm -r AndroidViewModel-master && rm androidviewmodel.zip
```
+Don't forget to restart the Android Studio.
+
+### Usage
+In the Android Studio right click inside the Projet window and select `File > New > AndroidViewModel Inloop > AVM Fragment`
+
+
+
diff --git a/build.gradle b/build.gradle
index bbdda21..51a9613 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,15 +1,17 @@
buildscript {
repositories {
jcenter()
+ google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.2.2'
+ classpath 'com.android.tools.build:gradle:3.3.1'
}
}
allprojects {
repositories {
jcenter()
+ google()
}
group = 'eu.inloop'
diff --git a/gradle.properties b/gradle.properties
index 9bedffc..f9ed904 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -17,4 +17,6 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
-VERSION_NAME=1.0.1
\ No newline at end of file
+android.enableJetifier=true
+android.useAndroidX=true
+VERSION_NAME=1.4.0
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 8fdb61d..ab096e7 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Sep 14 09:54:42 CEST 2016
+#Wed Feb 13 17:35:05 CET 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
diff --git a/gradlew b/gradlew
old mode 100644
new mode 100755
diff --git a/library/build.gradle b/library/build.gradle
index 30344aa..87a4ceb 100644
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -2,33 +2,35 @@ apply plugin: 'com.android.library'
apply plugin: 'maven'
android {
- compileSdkVersion 24
- buildToolsVersion '24.0.2'
+ compileSdkVersion 28
defaultConfig {
minSdkVersion 15
- targetSdkVersion 24
+ targetSdkVersion 28
versionCode 1
versionName VERSION_NAME
+ consumerProguardFiles 'proguard-rules.pro'
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_7
- targetCompatibility JavaVersion.VERSION_1_7
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
}
dataBinding {
- enabled = true;
+ enabled = true
}
}
dependencies {
- compile 'com.android.support:appcompat-v7:24.2.1'
+ implementation 'androidx.fragment:fragment:1.0.0'
+ implementation 'androidx.appcompat:appcompat:1.0.2'
+
+ androidTestImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test:runner:1.1.2-alpha01'
+ androidTestImplementation 'androidx.test:rules:1.1.2-alpha01'
}
task androidJavadocs(type: Javadoc) {
@@ -48,7 +50,6 @@ task androidSourcesJar(type: Jar) {
artifacts {
archives androidSourcesJar
- archives androidJavadocsJar
}
uploadArchives {
diff --git a/library/proguard-rules.pro b/library/proguard-rules.pro
index 9e42513..e32145a 100644
--- a/library/proguard-rules.pro
+++ b/library/proguard-rules.pro
@@ -15,3 +15,5 @@
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
+-dontwarn android.databinding.**
+-dontwarn eu.inloop.viewmodel.binding.**
\ No newline at end of file
diff --git a/library/src/androidTest/AndroidManifest.xml b/library/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..2e06fd1
--- /dev/null
+++ b/library/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
diff --git a/library/src/androidTest/java/eu/inloop/viewmodel/ViewModelActivityTest.java b/library/src/androidTest/java/eu/inloop/viewmodel/ViewModelActivityTest.java
new file mode 100644
index 0000000..15eb73f
--- /dev/null
+++ b/library/src/androidTest/java/eu/inloop/viewmodel/ViewModelActivityTest.java
@@ -0,0 +1,157 @@
+package eu.inloop.viewmodel;
+
+
+import android.content.pm.ActivityInfo;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Map;
+
+import eu.inloop.viewmodel.fixture.activity.VMTestActivity;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+
+@RunWith(AndroidJUnit4.class)
+public final class ViewModelActivityTest {
+
+ @Rule
+ public final ActivityTestRule mActivityTestRule =
+ new ActivityTestRule<>(VMTestActivity.class, false, false);
+
+ @SmallTest
+ @Test
+ public void viewModelActivity_onBindView_test() {
+ mActivityTestRule.launchActivity(VMTestActivity.makeIntent(InstrumentationRegistry.getContext(), true));
+
+ assertThat(mActivityTestRule.getActivityResult().getResultCode(), is(VMTestActivity.RESULT_CODE_OK));
+ }
+
+ @SmallTest
+ @Test
+ public void viewModelActivity_getViewModel_getView_test() {
+ mActivityTestRule.launchActivity(VMTestActivity.makeIntent(InstrumentationRegistry.getContext(), false));
+ mActivityTestRule.getActivity().getViewModel().loadData();
+
+ assertThat(mActivityTestRule.getActivityResult().getResultCode(), is(VMTestActivity.RESULT_CODE_OK));
+ }
+
+ @SmallTest
+ @Test
+ public void viewModelActivity_getViewModel_getViewOptional_test() {
+ mActivityTestRule.launchActivity(VMTestActivity.makeIntent(InstrumentationRegistry.getContext(), false));
+ mActivityTestRule.getActivity().getViewModel().loadDataOptional();
+
+ assertThat(mActivityTestRule.getActivityResult().getResultCode(), is(VMTestActivity.RESULT_CODE_OK));
+ }
+
+ @SmallTest
+ @Test
+ public void viewModelActivity_clearView_test() {
+ mActivityTestRule.launchActivity(VMTestActivity.makeIntent(InstrumentationRegistry.getContext(), false));
+ mActivityTestRule.getActivity().getViewModel().clearView();
+
+ assertThat(mActivityTestRule.getActivity().getViewModel().getView(), is(nullValue()));
+ }
+
+ @SmallTest
+ @Test
+ public void viewModelActivity_uniqueIdentifier_test() {
+ mActivityTestRule.launchActivity(VMTestActivity.makeIntent(InstrumentationRegistry.getContext(), false));
+ String uniqueIdentifier = mActivityTestRule.getActivity().getViewModel().getUniqueIdentifier();
+
+ assertThat(uniqueIdentifier, is(notNullValue()));
+ }
+
+ @SmallTest
+ @Test
+ public void viewModelActivity_fragment_getView_test() {
+ mActivityTestRule.launchActivity(VMTestActivity.makeIntent(InstrumentationRegistry.getContext(), false));
+
+ mActivityTestRule.getActivity().getTestFragment().getViewModel().loadData();
+
+ assertThat(mActivityTestRule.getActivityResult().getResultCode(), is(VMTestActivity.RESULT_CODE_OK));
+ }
+
+ @SmallTest
+ @Test
+ public void viewModelActivity_fragment_remove_test() {
+ mActivityTestRule.launchActivity(VMTestActivity.makeIntent(InstrumentationRegistry.getContext(), false));
+
+ String uniqueIdentifierActivity = mActivityTestRule.getActivity().getViewModel().getUniqueIdentifier();
+ String uniqueIdentifierFragment = mActivityTestRule.getActivity().getTestFragment().getViewModel().getUniqueIdentifier();
+
+ Map> viewModels =
+ mActivityTestRule.getActivity().getViewModelProvider().getViewModels();
+
+ assertThat(viewModels.containsKey(uniqueIdentifierActivity), is(true));
+ assertThat(viewModels.containsKey(uniqueIdentifierFragment), is(true));
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mActivityTestRule.getActivity().removeTestFragment();
+ }
+ });
+
+ //Check If ViewModel is removed after removing fragment
+ viewModels = mActivityTestRule.getActivity().getViewModelProvider().getViewModels();
+
+ assertThat(viewModels.containsKey(uniqueIdentifierActivity), is(true));
+ assertThat(viewModels.containsKey(uniqueIdentifierFragment), is(false));
+ }
+
+ @SmallTest
+ @Test
+ public void viewModelActivity_fragment_model_state_test() {
+ mActivityTestRule.launchActivity(VMTestActivity.makeIntent(InstrumentationRegistry.getContext(), false));
+
+ final int stateValue = 1;
+ mActivityTestRule.getActivity().getTestFragment().getViewModel().setStateValue(stateValue);
+
+ rotateScreen(1);
+
+ int actualStateValue = mActivityTestRule.getActivity().getTestFragment().getViewModel().getStateValue();
+
+ assertThat(stateValue, is(actualStateValue));
+ }
+
+ @MediumTest
+ @Test
+ public void viewModelActivity_instance_count_test() {
+ mActivityTestRule.launchActivity(VMTestActivity.makeIntent(InstrumentationRegistry.getContext(), false));
+
+ String uniqueIdentifierActivity = mActivityTestRule.getActivity().getViewModel().getUniqueIdentifier();
+ String uniqueIdentifierFragment = mActivityTestRule.getActivity().getTestFragment().getViewModel().getUniqueIdentifier();
+
+ rotateScreen(5);
+
+ Map> viewModels =
+ mActivityTestRule.getActivity().getViewModelProvider().getViewModels();
+
+ assertThat(viewModels.size(), is(2)); //activity + fragment
+
+ assertThat(viewModels.containsKey(uniqueIdentifierActivity), is(true));
+ assertThat(viewModels.containsKey(uniqueIdentifierFragment), is(true));
+ }
+
+ private void rotateScreen(int numOfTimes) {
+ for (int i = 0; i < numOfTimes; i++) {
+ mActivityTestRule.getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ mActivityTestRule.getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+ }
+
+}
diff --git a/library/src/androidTest/java/eu/inloop/viewmodel/fixture/activity/IVMTestActivityView.java b/library/src/androidTest/java/eu/inloop/viewmodel/fixture/activity/IVMTestActivityView.java
new file mode 100644
index 0000000..0d8b0d9
--- /dev/null
+++ b/library/src/androidTest/java/eu/inloop/viewmodel/fixture/activity/IVMTestActivityView.java
@@ -0,0 +1,9 @@
+package eu.inloop.viewmodel.fixture.activity;
+
+import eu.inloop.viewmodel.IView;
+
+public interface IVMTestActivityView extends IView {
+
+ void onLoadData(boolean loaded);
+
+}
diff --git a/library/src/androidTest/java/eu/inloop/viewmodel/fixture/activity/VMTestActivity.java b/library/src/androidTest/java/eu/inloop/viewmodel/fixture/activity/VMTestActivity.java
new file mode 100644
index 0000000..5e828f3
--- /dev/null
+++ b/library/src/androidTest/java/eu/inloop/viewmodel/fixture/activity/VMTestActivity.java
@@ -0,0 +1,72 @@
+package eu.inloop.viewmodel.fixture.activity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import android.widget.LinearLayout;
+
+import eu.inloop.viewmodel.base.ViewModelBaseActivity;
+import eu.inloop.viewmodel.fixture.fragment.VMTestFragment;
+
+public class VMTestActivity extends ViewModelBaseActivity implements IVMTestActivityView {
+
+ public static final int RESULT_CODE_OK = 1;
+ public static final String EXTRA_CALL_ON_BIND = "EXTRA_CALL_ON_BIND";
+
+ @NonNull
+ public static Intent makeIntent(@NonNull Context context, boolean callOnBindModel) {
+ Intent intent = new Intent(context, VMTestActivity.class);
+ intent.putExtra(EXTRA_CALL_ON_BIND, callOnBindModel);
+
+ return intent;
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout view = new LinearLayout(this);
+ view.setId(android.R.id.content);
+ setContentView(view);
+
+ if (savedInstanceState == null) {
+ addTestFragment();
+ }
+
+ setModelView(this);
+ }
+
+ public void addTestFragment() {
+ getSupportFragmentManager()
+ .beginTransaction()
+ .add(android.R.id.content, new VMTestFragment())
+ .commitNow();
+ }
+
+ public void removeTestFragment() {
+ getSupportFragmentManager()
+ .beginTransaction()
+ .remove(getTestFragment())
+ .commitNow();
+ }
+
+ @NonNull
+ public VMTestFragment getTestFragment() {
+ for (Fragment fragment : getSupportFragmentManager().getFragments()) {
+ if (fragment instanceof VMTestFragment) {
+ return (VMTestFragment) fragment;
+ }
+ }
+ throw new AssertionError("Fragment not found");
+ }
+
+ @Override
+ public void onLoadData(boolean loaded) {
+ setResult(RESULT_CODE_OK);
+ finish();
+ }
+
+}
diff --git a/library/src/androidTest/java/eu/inloop/viewmodel/fixture/activity/VMTestActivityViewModel.java b/library/src/androidTest/java/eu/inloop/viewmodel/fixture/activity/VMTestActivityViewModel.java
new file mode 100644
index 0000000..129d230
--- /dev/null
+++ b/library/src/androidTest/java/eu/inloop/viewmodel/fixture/activity/VMTestActivityViewModel.java
@@ -0,0 +1,39 @@
+package eu.inloop.viewmodel.fixture.activity;
+
+import android.os.Bundle;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import eu.inloop.viewmodel.AbstractViewModel;
+
+public class VMTestActivityViewModel extends AbstractViewModel {
+
+ private boolean mCallOnBind;
+
+ @Override
+ public void onCreate(@Nullable Bundle arguments, @Nullable Bundle savedInstanceState) {
+ super.onCreate(arguments, savedInstanceState);
+ if (arguments == null) {
+ throw new AssertionError("Arguments must be set for this ViewModel");
+ }
+ mCallOnBind = arguments.getBoolean(VMTestActivity.EXTRA_CALL_ON_BIND);
+ }
+
+ @Override
+ public void onBindView(@NonNull IVMTestActivityView view) {
+ super.onBindView(view);
+
+ if (mCallOnBind) {
+ loadData();
+ }
+ }
+
+ public void loadData() {
+ getView().onLoadData(true);
+ }
+
+ public void loadDataOptional() {
+ getViewOptional().onLoadData(true);
+ }
+
+}
diff --git a/library/src/androidTest/java/eu/inloop/viewmodel/fixture/fragment/IVMTestFragmentView.java b/library/src/androidTest/java/eu/inloop/viewmodel/fixture/fragment/IVMTestFragmentView.java
new file mode 100644
index 0000000..f8844d4
--- /dev/null
+++ b/library/src/androidTest/java/eu/inloop/viewmodel/fixture/fragment/IVMTestFragmentView.java
@@ -0,0 +1,9 @@
+package eu.inloop.viewmodel.fixture.fragment;
+
+import eu.inloop.viewmodel.IView;
+
+public interface IVMTestFragmentView extends IView {
+
+ void onLoadData(boolean loaded);
+
+}
diff --git a/library/src/androidTest/java/eu/inloop/viewmodel/fixture/fragment/VMTestFragment.java b/library/src/androidTest/java/eu/inloop/viewmodel/fixture/fragment/VMTestFragment.java
new file mode 100644
index 0000000..ca603af
--- /dev/null
+++ b/library/src/androidTest/java/eu/inloop/viewmodel/fixture/fragment/VMTestFragment.java
@@ -0,0 +1,34 @@
+package eu.inloop.viewmodel.fixture.fragment;
+
+import android.os.Bundle;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import eu.inloop.viewmodel.base.ViewModelBaseFragment;
+import eu.inloop.viewmodel.fixture.activity.VMTestActivity;
+
+public class VMTestFragment extends ViewModelBaseFragment
+ implements IVMTestFragmentView {
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ return new LinearLayout(getContext());
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ setModelView(this);
+ }
+
+ @Override
+ public void onLoadData(boolean loaded) {
+ requireActivity().setResult(VMTestActivity.RESULT_CODE_OK);
+ requireActivity().finish();
+ }
+}
diff --git a/library/src/androidTest/java/eu/inloop/viewmodel/fixture/fragment/VMTestFragmentViewModel.java b/library/src/androidTest/java/eu/inloop/viewmodel/fixture/fragment/VMTestFragmentViewModel.java
new file mode 100644
index 0000000..e8710d7
--- /dev/null
+++ b/library/src/androidTest/java/eu/inloop/viewmodel/fixture/fragment/VMTestFragmentViewModel.java
@@ -0,0 +1,42 @@
+package eu.inloop.viewmodel.fixture.fragment;
+
+import android.os.Bundle;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import eu.inloop.viewmodel.AbstractViewModel;
+
+public class VMTestFragmentViewModel extends AbstractViewModel {
+
+ private static final String STATE_INT = "STATE_INT";
+
+ private int mStateValue;
+
+ @Override
+ public void onCreate(@Nullable Bundle arguments, @Nullable Bundle savedInstanceState) {
+ super.onCreate(arguments, savedInstanceState);
+
+ if (savedInstanceState != null) {
+ mStateValue = savedInstanceState.getInt(STATE_INT);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle bundle) {
+ super.onSaveInstanceState(bundle);
+ bundle.putInt(STATE_INT, mStateValue);
+ }
+
+ public void setStateValue(int value) {
+ mStateValue = value;
+ }
+
+ public int getStateValue() {
+ return mStateValue;
+ }
+
+ public void loadData() {
+ getView().onLoadData(true);
+ }
+
+}
diff --git a/library/src/androidTest/java/sample/viewmodel/inloop/eu/viewmodelsample/ApplicationTest.java b/library/src/androidTest/java/sample/viewmodel/inloop/eu/viewmodelsample/ApplicationTest.java
deleted file mode 100644
index 3844758..0000000
--- a/library/src/androidTest/java/sample/viewmodel/inloop/eu/viewmodelsample/ApplicationTest.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package sample.viewmodel.inloop.eu.viewmodelsample;
-
-import android.app.Application;
-import android.test.ApplicationTestCase;
-
-/**
- * Testing Fundamentals
- */
-public class ApplicationTest extends ApplicationTestCase {
- public ApplicationTest() {
- super(Application.class);
- }
-}
\ No newline at end of file
diff --git a/library/src/main/java/eu/inloop/viewmodel/AbstractViewModel.java b/library/src/main/java/eu/inloop/viewmodel/AbstractViewModel.java
index 96c1e6c..560b4c3 100644
--- a/library/src/main/java/eu/inloop/viewmodel/AbstractViewModel.java
+++ b/library/src/main/java/eu/inloop/viewmodel/AbstractViewModel.java
@@ -3,10 +3,11 @@
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;
+import androidx.annotation.CallSuper;
+import androidx.annotation.CheckResult;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.View;
@@ -18,8 +19,15 @@ public abstract class AbstractViewModel {
@Nullable
private T mView;
+ @Nullable
+ private final Class> mClassType;
+
private boolean mBindViewWasCalled;
+ public AbstractViewModel() {
+ mClassType = ProxyViewHelper.getGenericType(getClass(), IView.class);
+ }
+
void setUniqueIdentifier(@NonNull final String uniqueIdentifier) {
mUniqueIdentifier = uniqueIdentifier;
}
@@ -59,11 +67,31 @@ public void onBindView(@NonNull T view) {
mView = view;
}
+ @CheckResult
@Nullable
public T getView() {
return mView;
}
+ /**
+ * Alternative to {@link #getView()}. This method will never return a null view - not even in case the current Fragment or
+ * Activity is already destroyed or between orientation change. It will return a dummy
+ * implementation in that case.
+ * @return the View instance which implements {@link T}. It's never null.
+ */
+ @CheckResult
+ @NonNull
+ public T getViewOptional() {
+ if (mView != null) {
+ return mView;
+ } else {
+ if (mClassType == null) {
+ throw new IllegalStateException("Your view must implement IView");
+ }
+ return ProxyViewHelper.init(mClassType);
+ }
+ }
+
@CallSuper
public void clearView() {
mView = null;
diff --git a/library/src/main/java/eu/inloop/viewmodel/IView.java b/library/src/main/java/eu/inloop/viewmodel/IView.java
index 4a06026..7bd2054 100644
--- a/library/src/main/java/eu/inloop/viewmodel/IView.java
+++ b/library/src/main/java/eu/inloop/viewmodel/IView.java
@@ -1,16 +1,31 @@
package eu.inloop.viewmodel;
-import android.support.annotation.Nullable;
+import android.app.Activity;
+import androidx.annotation.Nullable;
+import eu.inloop.viewmodel.base.ViewModelBaseActivity;
+import eu.inloop.viewmodel.base.ViewModelBaseFragment;
import eu.inloop.viewmodel.binding.ViewModelBindingConfig;
+/**
+ * Any Activity or Fragment that needs a ViewModel needs to implement this interface.
+ * You don't need to implement it yourself - use {@link ViewModelBaseActivity} and
+ * {@link ViewModelBaseFragment} instead.
+ */
public interface IView {
/**
- * This method is used for Data Binding to bind correct layout and variable atomatically
+ * This method is used for Data Binding to bind correct layout and variable automatically
* Can return null value in case that Data Binding is not used.
*
* @return defined ViewModelBinding Config for a specific screen.
*/
@Nullable
ViewModelBindingConfig getViewModelBindingConfig();
+
+ /**
+ * Implement this method to remove the ViewModel associated with the Fragment or Activity.
+ * This is usually implemented by calling {@link ViewModelHelper#removeViewModel(Activity)},
+ * see {@link ViewModelBaseActivity#removeViewModel()} and {@link ViewModelBaseFragment#removeViewModel()}.
+ */
+ void removeViewModel();
}
diff --git a/library/src/main/java/eu/inloop/viewmodel/IViewModelProvider.java b/library/src/main/java/eu/inloop/viewmodel/IViewModelProvider.java
index 70e4555..76db555 100644
--- a/library/src/main/java/eu/inloop/viewmodel/IViewModelProvider.java
+++ b/library/src/main/java/eu/inloop/viewmodel/IViewModelProvider.java
@@ -1,6 +1,6 @@
package eu.inloop.viewmodel;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
/**
* Your {@link android.app.Activity} must implement this interface if
diff --git a/library/src/main/java/eu/inloop/viewmodel/ProxyViewHelper.java b/library/src/main/java/eu/inloop/viewmodel/ProxyViewHelper.java
new file mode 100644
index 0000000..94d8ec4
--- /dev/null
+++ b/library/src/main/java/eu/inloop/viewmodel/ProxyViewHelper.java
@@ -0,0 +1,52 @@
+package eu.inloop.viewmodel;
+
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+
+public class ProxyViewHelper {
+
+ private static final class ProxyDummyClass {
+ }
+
+ private static final ProxyDummyClass sDummyClass = new ProxyDummyClass();
+ private static final Class[] sInterfaces = new Class[1];
+
+ private ProxyViewHelper() {
+ }
+
+ @SuppressWarnings("unchecked")
+ @NonNull
+ static T init(@NonNull Class> in) {
+ sInterfaces[0] = in;
+ return (T) Proxy.newProxyInstance(sDummyClass.getClass().getClassLoader(), sInterfaces, sInvocationHandler);
+ }
+
+ @Nullable
+ public static Class> getGenericType(@NonNull Class> in, @NonNull Class> whichExtends) {
+ final Type genericSuperclass = in.getGenericSuperclass();
+ if (genericSuperclass instanceof ParameterizedType) {
+ final Type[] typeArgs = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
+ for (Type arg : typeArgs) {
+ if (arg instanceof ParameterizedType) {
+ arg = ((ParameterizedType) arg).getRawType();
+ }
+ if (arg instanceof Class>) {
+ final Class> argClass = (Class>) arg;
+ if (whichExtends.isAssignableFrom(argClass)) {
+ return argClass;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private static final InvocationHandler sInvocationHandler = (proxy, method, args) -> null;
+
+}
diff --git a/library/src/main/java/eu/inloop/viewmodel/ViewModelHelper.java b/library/src/main/java/eu/inloop/viewmodel/ViewModelHelper.java
index 322cc88..b00234d 100644
--- a/library/src/main/java/eu/inloop/viewmodel/ViewModelHelper.java
+++ b/library/src/main/java/eu/inloop/viewmodel/ViewModelHelper.java
@@ -2,12 +2,12 @@
import android.app.Activity;
import android.content.Intent;
-import android.databinding.DataBindingUtil;
-import android.databinding.ViewDataBinding;
+import androidx.databinding.DataBindingUtil;
+import androidx.databinding.ViewDataBinding;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.app.Fragment;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
@@ -34,7 +34,7 @@ public class ViewModelHelper> {
/**
* Call from {@link android.app.Activity#onCreate(android.os.Bundle)} or
- * {@link android.support.v4.app.Fragment#onCreate(android.os.Bundle)}
+ * {@link androidx.core.app.Fragment#onCreate(android.os.Bundle)}
*
* @param activity parent activity
* @param savedInstanceState savedInstance state from {@link Activity#onCreate(Bundle)} or
@@ -79,14 +79,14 @@ public void onCreate(@NonNull Activity activity,
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"); //NON-NLS
+ Log.d("model", "Fragment recreated by system or ViewModelStatePagerAdapter - restoring viewmodel"); //NON-NLS
}
mViewModel.onCreate(arguments, savedInstanceState);
}
}
/**
- * Call from {@link android.support.v4.app.Fragment#onViewCreated(android.view.View, android.os.Bundle)}
+ * Call from {@link androidx.core.app.Fragment#onViewCreated(android.view.View, android.os.Bundle)}
* or {@link android.app.Activity#onCreate(android.os.Bundle)}
*
* @param view view
@@ -133,8 +133,8 @@ public void performBinding(@NonNull final IView bindingView) {
}
/**
- * 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
+ * Use in case this model is associated with an {@link androidx.core.app.Fragment}
+ * Call from {@link androidx.core.app.Fragment#onDestroyView()}. Use in case model is associated
* with Fragment
*
* @param fragment fragment
@@ -152,8 +152,8 @@ public void onDestroyView(@NonNull Fragment fragment) {
}
/**
- * Use in case this model is associated with an {@link android.support.v4.app.Fragment}
- * Call from {@link android.support.v4.app.Fragment#onDestroy()}
+ * Use in case this model is associated with an {@link androidx.core.app.Fragment}
+ * Call from {@link androidx.core.app.Fragment#onDestroy()}
*
* @param fragment fragment
*/
@@ -162,15 +162,15 @@ public void onDestroy(@NonNull final Fragment fragment) {
//no viewmodel for this fragment
return;
}
- if (fragment.getActivity().isFinishing()) {
- removeViewModel(fragment.getActivity());
+ if (fragment.requireActivity().isFinishing()) {
+ removeViewModel(fragment.requireActivity());
} else if (fragment.isRemoving() && !mOnSaveInstanceCalled) {
// The fragment can be still in backstack even if isRemoving() is true.
// We check mOnSaveInstanceCalled - if this was not called then the fragment is totally removed.
if (BuildConfig.DEBUG) {
Log.d("mode", "Removing viewmodel - fragment replaced"); //NON-NLS
}
- removeViewModel(fragment.getActivity());
+ removeViewModel(fragment.requireActivity());
}
mBinding = null;
}
@@ -194,7 +194,7 @@ public void onDestroy(@NonNull final Activity activity) {
}
/**
- * Call from {@link android.app.Activity#onStop()} or {@link android.support.v4.app.Fragment#onStop()}
+ * Call from {@link android.app.Activity#onStop()} or {@link androidx.core.app.Fragment#onStop()}
*/
public void onStop() {
if (mViewModel == null) {
@@ -205,7 +205,7 @@ public void onStop() {
}
/**
- * Call from {@link android.app.Activity#onStart()} ()} or {@link android.support.v4.app.Fragment#onStart()} ()}
+ * Call from {@link android.app.Activity#onStart()} ()} or {@link androidx.core.app.Fragment#onStart()} ()}
*/
public void onStart() {
if (mViewModel == null) {
@@ -234,7 +234,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)}.
+ * or {@link androidx.core.app.Fragment#onSaveInstanceState(android.os.Bundle)}.
* This allows the model to save its state.
*
* @param bundle bundle
@@ -252,7 +252,7 @@ public ViewDataBinding getBinding() {
return mBinding;
}
- private void removeViewModel(@NonNull final Activity activity) {
+ public void removeViewModel(@NonNull final Activity activity) {
if (mViewModel != null && !mModelRemoved) {
final ViewModelProvider viewModelProvider = getViewModelProvider(activity).getViewModelProvider();
if (null == viewModelProvider) {
diff --git a/library/src/main/java/eu/inloop/viewmodel/ViewModelProvider.java b/library/src/main/java/eu/inloop/viewmodel/ViewModelProvider.java
index c541de4..ab07ecb 100644
--- a/library/src/main/java/eu/inloop/viewmodel/ViewModelProvider.java
+++ b/library/src/main/java/eu/inloop/viewmodel/ViewModelProvider.java
@@ -1,15 +1,18 @@
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 androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.fragment.app.FragmentActivity;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.Map;
/**
* Create and keep this class inside your Activity. Store it
- * in {@link android.support.v4.app.FragmentActivity#onRetainCustomNonConfigurationInstance()
- * and restore in {@link android.support.v4.app.FragmentActivity#onCreate(android.os.Bundle)} before
+ * in {@link androidx.core.app.FragmentActivity#onRetainCustomNonConfigurationInstance()
+ * and restore in {@link androidx.core.app.FragmentActivity#onCreate(android.os.Bundle)} before
* calling the super implemenentation.
*/
public class ViewModelProvider {
@@ -49,6 +52,12 @@ public synchronized void removeAllViewModels() {
mViewModelCache.clear();
}
+ @VisibleForTesting
+ @NonNull
+ Map> getViewModels() {
+ return Collections.unmodifiableMap(mViewModelCache);
+ }
+
@SuppressWarnings("unchecked")
@NonNull
public synchronized ViewModelWrapper getViewModel(@NonNull final String modelIdentifier,
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 bb59d88..f7b895a 100644
--- a/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseActivity.java
+++ b/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseActivity.java
@@ -1,13 +1,15 @@
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 androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import eu.inloop.viewmodel.AbstractViewModel;
import eu.inloop.viewmodel.IView;
+import eu.inloop.viewmodel.ProxyViewHelper;
import eu.inloop.viewmodel.ViewModelHelper;
+import eu.inloop.viewmodel.binding.ViewModelBindingConfig;
public abstract class ViewModelBaseActivity> extends ViewModelBaseEmptyActivity implements IView {
@@ -18,7 +20,14 @@ public abstract class ViewModelBaseActivity> viewModelClass = getViewModelClass();
+ // try to extract the ViewModel class from the implementation
+ if (viewModelClass == null) {
+ //noinspection unchecked
+ viewModelClass = (Class extends AbstractViewModel>) ProxyViewHelper.getGenericType(getClass(), AbstractViewModel.class);
+ }
+ mViewModeHelper.onCreate(this, savedInstanceState, viewModelClass, getIntent().getExtras());
}
/**
@@ -31,7 +40,9 @@ public void setModelView(@NonNull final T view) {
}
@Nullable
- public abstract Class getViewModelClass();
+ public Class getViewModelClass() {
+ return null;
+ }
@CallSuper
@Override
@@ -70,4 +81,14 @@ public R getViewModel() {
return mViewModeHelper.getViewModel();
}
+ @Override
+ public void removeViewModel() {
+ mViewModeHelper.removeViewModel(this);
+ }
+
+ @Nullable
+ @Override
+ public ViewModelBindingConfig getViewModelBindingConfig() {
+ return null;
+ }
}
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 35ebd20..f98db59 100644
--- a/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseEmptyActivity.java
+++ b/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseEmptyActivity.java
@@ -1,9 +1,9 @@
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;
+import androidx.annotation.CallSuper;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
import eu.inloop.viewmodel.IViewModelProvider;
import eu.inloop.viewmodel.ViewModelProvider;
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 354b7ed..19d57b9 100644
--- a/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseFragment.java
+++ b/library/src/main/java/eu/inloop/viewmodel/base/ViewModelBaseFragment.java
@@ -1,65 +1,76 @@
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;
+import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
import android.view.View;
import eu.inloop.viewmodel.AbstractViewModel;
import eu.inloop.viewmodel.IView;
+import eu.inloop.viewmodel.ProxyViewHelper;
import eu.inloop.viewmodel.ViewModelHelper;
+import eu.inloop.viewmodel.binding.ViewModelBindingConfig;
public abstract class ViewModelBaseFragment> extends Fragment implements IView {
@NonNull
- private final ViewModelHelper mViewModeHelper = new ViewModelHelper<>();
+ private final ViewModelHelper mViewModelHelper = new ViewModelHelper<>();
@CallSuper
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- getViewModeHelper().onCreate(getActivity(), savedInstanceState, getViewModelClass(), getArguments());
+
+ Class extends AbstractViewModel> viewModelClass = getViewModelClass();
+ // try to extract the ViewModel class from the implementation
+ if (viewModelClass == null) {
+ //noinspection unchecked
+ viewModelClass = (Class extends AbstractViewModel>) ProxyViewHelper.getGenericType(getClass(), AbstractViewModel.class);
+ }
+ getViewModelHelper().onCreate(requireActivity(), savedInstanceState, viewModelClass, getArguments());
}
@CallSuper
@Override
public void onSaveInstanceState(@NonNull final Bundle outState) {
super.onSaveInstanceState(outState);
- getViewModeHelper().onSaveInstanceState(outState);
+ getViewModelHelper().onSaveInstanceState(outState);
}
@CallSuper
@Override
public void onStart() {
super.onStart();
- getViewModeHelper().onStart();
+ getViewModelHelper().onStart();
}
@CallSuper
@Override
public void onStop() {
super.onStop();
- getViewModeHelper().onStop();
+ getViewModelHelper().onStop();
}
@CallSuper
@Override
public void onDestroyView() {
- getViewModeHelper().onDestroyView(this);
+ getViewModelHelper().onDestroyView(this);
super.onDestroyView();
}
@CallSuper
@Override
public void onDestroy() {
- getViewModeHelper().onDestroy(this);
+ getViewModelHelper().onDestroy(this);
super.onDestroy();
}
@Nullable
- public abstract Class getViewModelClass();
+ public Class getViewModelClass() {
+ return null;
+ }
/**
* @see ViewModelHelper#getViewModel()
@@ -67,12 +78,23 @@ public void onDestroy() {
@NonNull
@SuppressWarnings("unused")
public R getViewModel() {
- return getViewModeHelper().getViewModel();
+ return getViewModelHelper().getViewModel();
+ }
+
+ @Nullable
+ @Override
+ public ViewModelBindingConfig getViewModelBindingConfig() {
+ return null;
}
@NonNull
- public ViewModelHelper getViewModeHelper() {
- return mViewModeHelper;
+ public ViewModelHelper getViewModelHelper() {
+ return mViewModelHelper;
+ }
+
+ @Override
+ public void removeViewModel() {
+ mViewModelHelper.removeViewModel(requireActivity());
}
/**
@@ -82,6 +104,6 @@ public ViewModelHelper getViewModeHelper() {
* @param view view
*/
protected void setModelView(@NonNull final T view) {
- getViewModeHelper().setView(view);
+ getViewModelHelper().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
index 7b8fca8..4fabe9e 100644
--- a/library/src/main/java/eu/inloop/viewmodel/binding/ViewModelBaseBindingFragment.java
+++ b/library/src/main/java/eu/inloop/viewmodel/binding/ViewModelBaseBindingFragment.java
@@ -1,13 +1,13 @@
package eu.inloop.viewmodel.binding;
-import android.databinding.ViewDataBinding;
+import androidx.databinding.ViewDataBinding;
import android.os.Bundle;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import org.jetbrains.annotations.NotNull;
+import androidx.annotation.NonNull;
import eu.inloop.viewmodel.AbstractViewModel;
import eu.inloop.viewmodel.IView;
@@ -20,14 +20,14 @@ public abstract class ViewModelBaseBindingFragment
diff --git a/sample/src/main/java/eu/inloop/viewmodel/sample/activity/MainActivity.java b/sample/src/main/java/eu/inloop/viewmodel/sample/activity/MainActivity.java
index 8e027ed..5d4ed8a 100644
--- a/sample/src/main/java/eu/inloop/viewmodel/sample/activity/MainActivity.java
+++ b/sample/src/main/java/eu/inloop/viewmodel/sample/activity/MainActivity.java
@@ -3,7 +3,6 @@
import android.os.Bundle;
import butterknife.ButterKnife;
-import eu.inloop.viewmodel.base.ViewModelBaseActivity;
import eu.inloop.viewmodel.base.ViewModelBaseEmptyActivity;
import eu.inloop.viewmodel.sample.R;
import eu.inloop.viewmodel.sample.fragment.UserListFragment;
@@ -15,7 +14,7 @@ public class MainActivity extends ViewModelBaseEmptyActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
- ButterKnife.inject(this);
+ ButterKnife.bind(this);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().replace(R.id.root_content, new UserListFragment(), "user-list-fragment").commit();
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
index 9ea4528..2967890 100644
--- a/sample/src/main/java/eu/inloop/viewmodel/sample/activity/SampleBindingActivity.java
+++ b/sample/src/main/java/eu/inloop/viewmodel/sample/activity/SampleBindingActivity.java
@@ -12,15 +12,14 @@
public class SampleBindingActivity extends ViewModelBaseEmptyActivity {
public static Intent newIntent(Context context) {
- Intent intent = new Intent(context, SampleBindingActivity.class);
- return intent;
+ return new Intent(context, SampleBindingActivity.class);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
- ButterKnife.inject(this);
+ ButterKnife.bind(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/activity/ViewPagerActivity.java b/sample/src/main/java/eu/inloop/viewmodel/sample/activity/ViewPagerActivity.java
index b8e9321..2e56405 100644
--- a/sample/src/main/java/eu/inloop/viewmodel/sample/activity/ViewPagerActivity.java
+++ b/sample/src/main/java/eu/inloop/viewmodel/sample/activity/ViewPagerActivity.java
@@ -1,29 +1,33 @@
package eu.inloop.viewmodel.sample.activity;
import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v4.view.ViewPager;
-import eu.inloop.viewmodel.base.ViewModelBaseActivity;
+
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.viewpager.widget.ViewPager;
+import butterknife.BindView;
+import butterknife.ButterKnife;
import eu.inloop.viewmodel.base.ViewModelBaseEmptyActivity;
import eu.inloop.viewmodel.sample.R;
import eu.inloop.viewmodel.sample.fragment.PagerFragment;
+import eu.inloop.viewmodel.support.ViewModelStatePagerAdapter;
public class ViewPagerActivity extends ViewModelBaseEmptyActivity {
+ @BindView(R.id.pager)
+ ViewPager mViewPager;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pager);
-
- final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
- viewPager.setAdapter(new TestPagerAdapter(getSupportFragmentManager()));
+ ButterKnife.bind(this);
+ mViewPager.setAdapter(new TestPagerAdapter(getSupportFragmentManager()));
}
- private final static class TestPagerAdapter extends FragmentStatePagerAdapter {
- public TestPagerAdapter(FragmentManager fm) {
+ private final static class TestPagerAdapter extends ViewModelStatePagerAdapter {
+ TestPagerAdapter(FragmentManager fm) {
super(fm);
}
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 a866508..daf7d60 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
@@ -1,7 +1,8 @@
package eu.inloop.viewmodel.sample.fragment;
import android.os.Bundle;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -10,13 +11,12 @@
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;
import eu.inloop.viewmodel.sample.viewmodel.view.IPageView;
-public class PagerFragment extends ViewModelBaseFragment {
+public class PagerFragment extends ViewModelBaseFragment implements IPageView {
public static PagerFragment newInstance(int position) {
final Bundle bundle = new Bundle();
@@ -28,19 +28,15 @@ public static PagerFragment newInstance(int position) {
@Nullable
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_pager, container, false);
}
@Override
- public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
((TextView)view.findViewById(R.id.text)).setText(Integer.toString(getArguments().getInt("position")));
- }
-
- @Override
- public Class getViewModelClass() {
- return PageModel.class;
+ setModelView(this);
}
@Override
@@ -48,13 +44,7 @@ public void onDestroy() {
super.onDestroy();
// watch for memory leaks
- RefWatcher refWatcher = SampleApplication.getRefWatcher(getActivity());
+ RefWatcher refWatcher = SampleApplication.getRefWatcher(requireActivity());
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
index 6db4912..934666f 100644
--- a/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/SampleBindingFragment.java
+++ b/sample/src/main/java/eu/inloop/viewmodel/sample/fragment/SampleBindingFragment.java
@@ -1,8 +1,11 @@
package eu.inloop.viewmodel.sample.fragment;
-import android.support.annotation.Nullable;
-import android.support.v4.app.Fragment;
+import android.os.Bundle;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import android.view.View;
+import androidx.fragment.app.Fragment;
import eu.inloop.viewmodel.binding.ViewModelBaseBindingFragment;
import eu.inloop.viewmodel.binding.ViewModelBindingConfig;
import eu.inloop.viewmodel.sample.R;
@@ -22,14 +25,13 @@ public SampleBindingFragment() {
}
@Override
- public ViewModelBindingConfig getViewModelBindingConfig() {
- return new ViewModelBindingConfig(R.layout.fragment_sample_binding, getActivity());
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ setModelView(this);
}
- @Nullable
@Override
- public Class getViewModelClass() {
- return SampleBindingViewModel.class;
+ public ViewModelBindingConfig getViewModelBindingConfig() {
+ return new ViewModelBindingConfig(R.layout.fragment_sample_binding, requireActivity());
}
-
}
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 2b53568..031a285 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
@@ -1,7 +1,7 @@
package eu.inloop.viewmodel.sample.fragment;
import android.os.Bundle;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -9,7 +9,6 @@
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;
@@ -33,18 +32,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- ButterKnife.inject(this, view);
+ ButterKnife.bind(this, view);
setModelView(this);
}
-
- @Override
- 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 1187c03..d415492 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
@@ -2,7 +2,8 @@
import android.content.Intent;
import android.os.Bundle;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -17,10 +18,9 @@
import java.util.ArrayList;
import java.util.List;
+import butterknife.BindView;
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;
@@ -30,13 +30,13 @@
public class UserListFragment extends ViewModelBaseFragment implements IUserListView {
- @InjectView(android.R.id.progress)
+ @BindView(android.R.id.progress)
View mProgressView;
- @InjectView(R.id.progress_text)
+ @BindView(R.id.progress_text)
TextView mProgressText;
- @InjectView(android.R.id.list)
+ @BindView(android.R.id.list)
ListView mListview;
- @InjectView(R.id.open_binding_fragment)
+ @BindView(R.id.open_binding_fragment)
Button mOpenBindingFragment;
private ArrayAdapter mAdapter;
@@ -44,51 +44,46 @@ public class UserListFragment extends ViewModelBaseFragment(getActivity(), android.R.layout.simple_list_item_1, android.R.id.text1, new ArrayList());
+ mAdapter = new ArrayAdapter<>(requireActivity(), android.R.layout.simple_list_item_1, android.R.id.text1, new ArrayList());
}
@Override
- public Class getViewModelClass() {
- return UserListViewModel.class;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_userlist, container, false);
- ButterKnife.inject(this, view);
+ ButterKnife.bind(this, view);
final View headerView = inflater.inflate(R.layout.view_header_info, null, false);
headerView.findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- getFragmentManager().beginTransaction().replace(R.id.root_content, SampleBundleFragment.newInstance(1234), "empty-fragment").addToBackStack(null).commit();
+ requireFragmentManager().beginTransaction().replace(R.id.root_content, SampleBundleFragment.newInstance(1234), "empty-fragment").addToBackStack(null).commit();
}
});
headerView.findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- getActivity().finish();
- getActivity().startActivity(getActivity().getIntent());
+ requireActivity().finish();
+ requireActivity().startActivity(requireActivity().getIntent());
}
});
headerView.findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- startActivity(new Intent(getContext(), ViewPagerActivity.class));
+ startActivity(new Intent(requireContext(), ViewPagerActivity.class));
}
});
mListview.addHeaderView(headerView, null, false);
mOpenBindingFragment.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- startActivity(SampleBindingActivity.newIntent(getActivity()));
+ startActivity(SampleBindingActivity.newIntent(requireActivity()));
}
});
return view;
}
@Override
- public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mListview.setAdapter(mAdapter);
mListview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@@ -125,13 +120,7 @@ public void onDestroy() {
super.onDestroy();
// watch for memory leaks
- RefWatcher refWatcher = SampleApplication.getRefWatcher(getActivity());
+ RefWatcher refWatcher = SampleApplication.getRefWatcher(requireActivity());
refWatcher.watch(this);
}
-
- @Nullable
- @Override
- public ViewModelBindingConfig getViewModelBindingConfig() {
- return null;
- }
}
diff --git a/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/PageModel.java b/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/PageModel.java
index f6a515f..a238f1e 100644
--- a/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/PageModel.java
+++ b/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/PageModel.java
@@ -1,7 +1,15 @@
package eu.inloop.viewmodel.sample.viewmodel;
+import android.os.Bundle;
+import androidx.annotation.Nullable;
+
import eu.inloop.viewmodel.AbstractViewModel;
import eu.inloop.viewmodel.sample.viewmodel.view.IPageView;
public class PageModel extends AbstractViewModel {
+
+ @Override
+ public void onCreate(@Nullable Bundle arguments, @Nullable Bundle savedInstanceState) {
+ super.onCreate(arguments, savedInstanceState);
+ }
}
diff --git a/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/SampleArgumentViewModel.java b/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/SampleArgumentViewModel.java
index a8275a5..c31e0d3 100644
--- a/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/SampleArgumentViewModel.java
+++ b/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/SampleArgumentViewModel.java
@@ -1,7 +1,7 @@
package eu.inloop.viewmodel.sample.viewmodel;
import android.os.Bundle;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import android.util.Log;
import eu.inloop.viewmodel.AbstractViewModel;
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
index 40a74e5..21f832f 100644
--- a/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/SampleBindingViewModel.java
+++ b/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/SampleBindingViewModel.java
@@ -1,8 +1,8 @@
package eu.inloop.viewmodel.sample.viewmodel;
-import android.databinding.ObservableField;
+import androidx.databinding.ObservableField;
import android.os.Bundle;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import eu.inloop.viewmodel.AbstractViewModel;
import eu.inloop.viewmodel.sample.viewmodel.view.ISampleBindingView;
diff --git a/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/UserListViewModel.java b/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/UserListViewModel.java
index 04f4581..58e5a0c 100644
--- a/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/UserListViewModel.java
+++ b/sample/src/main/java/eu/inloop/viewmodel/sample/viewmodel/UserListViewModel.java
@@ -1,9 +1,10 @@
package eu.inloop.viewmodel.sample.viewmodel;
+import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
@@ -45,12 +46,11 @@ public void onBindView(@NonNull IUserListView view) {
}
}
+ @SuppressLint("StaticFieldLeak")
private void loadUsers() {
mLoadingUsers = true;
mCurrentLoadingProgress = 0;
- if (getView() != null) {
- getView().showLoading(mCurrentLoadingProgress);
- }
+ getViewOptional().showLoading(mCurrentLoadingProgress);
new AsyncTask>() {
@Override
@@ -74,9 +74,7 @@ protected List doInBackground(Void... voids) {
protected void onProgressUpdate(Float... values) {
super.onProgressUpdate(values);
mCurrentLoadingProgress = values[0];
- if (getView() != null) {
- getView().showLoading(mCurrentLoadingProgress);
- }
+ getViewOptional().showLoading(mCurrentLoadingProgress);
}
@Override
@@ -84,22 +82,19 @@ protected void onPostExecute(List s) {
super.onPostExecute(s);
mLoadedUsers = s;
mLoadingUsers = false;
- if (getView() != null) {
- getView().showUsers(s);
- getView().hideProgress();
- }
+ getViewOptional().showUsers(s);
+ getViewOptional().hideProgress();
}
}.execute();
}
+ @SuppressLint("StaticFieldLeak")
public void deleteUser(final int position) {
if (position > mLoadedUsers.size() - 1) {
return;
}
mLoadedUsers.set(position, "Deleting in 5 seconds...");
- if (getView() != null) {
- getView().showUsers(mLoadedUsers);
- }
+ getViewOptional().showUsers(mLoadedUsers);
final String itemToDelete = mLoadedUsers.get(position);
new AsyncTask() {
@@ -118,9 +113,7 @@ protected Void doInBackground(Void... voids) {
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
- if (getView() != null) {
- getView().showUsers(mLoadedUsers);
- }
+ getViewOptional().showUsers(mLoadedUsers);
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
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 ab4112b..2e5267b 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
@@ -3,9 +3,6 @@
import eu.inloop.viewmodel.IView;
import eu.inloop.viewmodel.binding.ViewModelBindingConfig;
-public class IPageView implements IView {
- @Override
- public ViewModelBindingConfig getViewModelBindingConfig() {
- return null;
- }
+public interface IPageView extends IView {
+ ViewModelBindingConfig getViewModelBindingConfig();
}
diff --git a/sample/src/main/res/layout/activity_pager.xml b/sample/src/main/res/layout/activity_pager.xml
index 0c61343..e6e6d08 100644
--- a/sample/src/main/res/layout/activity_pager.xml
+++ b/sample/src/main/res/layout/activity_pager.xml
@@ -3,7 +3,7 @@
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
-
diff --git a/template/AVM_Inloop/avm_inloop_template_preview.png b/template/AVM_Inloop/avm_inloop_template_preview.png
new file mode 100644
index 0000000..4216781
Binary files /dev/null and b/template/AVM_Inloop/avm_inloop_template_preview.png differ
diff --git a/template/AVM_Inloop/globals.xml.ftl b/template/AVM_Inloop/globals.xml.ftl
new file mode 100644
index 0000000..691656d
--- /dev/null
+++ b/template/AVM_Inloop/globals.xml.ftl
@@ -0,0 +1,5 @@
+
+
+
+ <#include "../../activities/common/common_globals.xml.ftl" />
+
\ No newline at end of file
diff --git a/template/AVM_Inloop/recipe.xml.ftl b/template/AVM_Inloop/recipe.xml.ftl
new file mode 100644
index 0000000..2747958
--- /dev/null
+++ b/template/AVM_Inloop/recipe.xml.ftl
@@ -0,0 +1,48 @@
+
+
+
+ <#if appCompat && !(hasDependency('eu.inloop:androidviewmodel'))>
+
+ #if>
+
+ <#if screenType == "Fragment">
+
+
+ #if>
+ <#if screenType == "BindingFragment">
+
+
+ #if>
+
+ <#if generateViewInterface>
+
+ #if>
+
+
+ <#if scrPackage != "">
+
+ <#else>
+
+ #if>
+
+ <#if vmPackage != "">
+
+ <#else>
+
+ #if>
+
+ <#if vPackage != "">
+
+ <#else>
+
+ #if>
+
+
+
+
\ No newline at end of file
diff --git a/template/AVM_Inloop/root/src/app_package/BindingFragment.java.ftl b/template/AVM_Inloop/root/src/app_package/BindingFragment.java.ftl
new file mode 100644
index 0000000..429d61e
--- /dev/null
+++ b/template/AVM_Inloop/root/src/app_package/BindingFragment.java.ftl
@@ -0,0 +1,45 @@
+package ${packageName}<#if scrPackage != "">.${scrPackage}#if>;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.View;
+<#if vPackage != "">
+ import ${packageName}<#if vPackage != "">.${vPackage?replace('/','.')}#if>.I${viewModelClass?replace('ViewModel', 'View')};
+<#else>
+ import eu.inloop.viewmodel.IView;
+#if>
+import eu.inloop.viewmodel.binding.ViewModelBaseBindingFragment;
+import eu.inloop.viewmodel.binding.ViewModelBindingConfig;
+import ${packageName}.databinding.${underscoreToCamelCase(layoutName)}Binding;
+import ${packageName}.R;
+import ${packageName}<#if vmPackage != "">.${vmPackage?replace('/','.')}#if>.${viewModelClass};
+
+<#if vPackage != "">
+ public class ${screenClass}
+ extends ViewModelBase${screenType}
+ implements I${viewModelClass?replace('ViewModel', 'View')} {
+<#else>
+ public class ${screenClass} extends ViewModelBase${screenType} {
+#if>
+
+
+ public static ${screenClass} newInstance() {
+ final Bundle bundle = new Bundle();
+ // set arguments
+ final ${screenClass} fragment = new ${screenClass}();
+ fragment.setArguments(bundle);
+ return fragment;
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ setModelView(this);
+ }
+
+ @Override
+ public ViewModelBindingConfig getViewModelBindingConfig() {
+ return new ViewModelBindingConfig(R.layout.${layoutName}, getActivity());
+ }
+
+}
\ No newline at end of file
diff --git a/template/AVM_Inloop/root/src/app_package/Fragment.java.ftl b/template/AVM_Inloop/root/src/app_package/Fragment.java.ftl
new file mode 100644
index 0000000..97ce736
--- /dev/null
+++ b/template/AVM_Inloop/root/src/app_package/Fragment.java.ftl
@@ -0,0 +1,45 @@
+package ${packageName}<#if scrPackage != "">.${scrPackage}#if>;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+<#if vPackage != "">
+ import ${packageName}<#if vPackage != "">.${vPackage?replace('/','.')}#if>.I${viewModelClass?replace('ViewModel', 'View')};
+<#else>
+ import eu.inloop.viewmodel.IView;
+#if>
+import eu.inloop.viewmodel.base.ViewModelBaseFragment;
+import ${packageName}.R;
+import ${packageName}<#if vmPackage != "">.${vmPackage?replace('/','.')}#if>.${viewModelClass};
+
+<#if vPackage != "">
+ public class ${screenClass}
+ extends ViewModelBase${screenType}
+ implements I${viewModelClass?replace('ViewModel', 'View')} {
+<#else>
+ public class ${screenClass} extends ViewModelBase${screenType} {
+#if>
+
+ public static ${screenClass} newInstance() {
+ final Bundle bundle = new Bundle();
+ // set arguments
+ final ${screenClass} fragment = new ${screenClass}();
+ fragment.setArguments(bundle);
+ return fragment;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.${layoutName}, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ setModelView(this);
+ }
+
+}
\ No newline at end of file
diff --git a/template/AVM_Inloop/root/src/app_package/ViewInterface.java.ftl b/template/AVM_Inloop/root/src/app_package/ViewInterface.java.ftl
new file mode 100644
index 0000000..d79121b
--- /dev/null
+++ b/template/AVM_Inloop/root/src/app_package/ViewInterface.java.ftl
@@ -0,0 +1,8 @@
+
+package ${packageName}<#if vmPackage != "">.${vPackage?replace('/','.')}#if>;
+
+import eu.inloop.viewmodel.IView;
+
+public interface I${viewModelClass?replace('ViewModel', 'View')} extends IView {
+
+}
\ No newline at end of file
diff --git a/template/AVM_Inloop/root/src/app_package/ViewModel.java.ftl b/template/AVM_Inloop/root/src/app_package/ViewModel.java.ftl
new file mode 100644
index 0000000..1e57b44
--- /dev/null
+++ b/template/AVM_Inloop/root/src/app_package/ViewModel.java.ftl
@@ -0,0 +1,24 @@
+
+package ${packageName}<#if vmPackage != "">.${vmPackage}#if>;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import eu.inloop.viewmodel.AbstractViewModel;
+<#if vPackage != "">
+ import ${packageName}<#if vPackage != "">.${vPackage?replace('/','.')}#if>.I${viewModelClass?replace('ViewModel', 'View')};
+<#else>
+ import eu.inloop.viewmodel.IView;
+#if>
+
+<#if vPackage != "">
+ public class ${viewModelClass} extends AbstractViewModel {
+<#else>
+ public class ${viewModelClass} extends AbstractViewModel {
+#if>
+
+ @Override
+ public void onCreate(@Nullable Bundle arguments, @Nullable Bundle savedInstanceState) {
+ super.onCreate(arguments, savedInstanceState);
+
+ }
+}
\ No newline at end of file
diff --git a/template/AVM_Inloop/root/src/app_package/binding_layout.xml.ftl b/template/AVM_Inloop/root/src/app_package/binding_layout.xml.ftl
new file mode 100644
index 0000000..f90065f
--- /dev/null
+++ b/template/AVM_Inloop/root/src/app_package/binding_layout.xml.ftl
@@ -0,0 +1,19 @@
+
+.${scrPackage?replace('/','.')}#if>.${screenClass}">
+
+
+ ${vmPackage?replace('/','.')}.#if>${viewModelClass}"/>
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/template/AVM_Inloop/root/src/app_package/layout.xml.ftl b/template/AVM_Inloop/root/src/app_package/layout.xml.ftl
new file mode 100644
index 0000000..f0bf876
--- /dev/null
+++ b/template/AVM_Inloop/root/src/app_package/layout.xml.ftl
@@ -0,0 +1,9 @@
+.${scrPackage?replace('/','.')}#if>.${screenClass}"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+
\ No newline at end of file
diff --git a/template/AVM_Inloop/template.xml b/template/AVM_Inloop/template.xml
new file mode 100644
index 0000000..110cae4
--- /dev/null
+++ b/template/AVM_Inloop/template.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ avm_inloop_template_preview.png
+
+
+
+
+
+
\ No newline at end of file
diff --git a/template/create-new-template-preview.png b/template/create-new-template-preview.png
new file mode 100644
index 0000000..1d57607
Binary files /dev/null and b/template/create-new-template-preview.png differ
diff --git a/template/template-preview.png b/template/template-preview.png
new file mode 100644
index 0000000..70f9526
Binary files /dev/null and b/template/template-preview.png differ