[go: nahoru, domu]

Allow ViewModelStoreOwner to provide a default Factory

Use a default method to allow ViewModelStoreOwners to
optionally set a default ViewModelProvider.Factory that
can be used with new, concise ViewModelProvider
constructors.

Test: new tests pass
BUG: 110936593
Change-Id: Ie15b6ebb119f1f7bcbbbdb5209024fddf3452538
diff --git a/lifecycle/lifecycle-viewmodel/api/2.2.0-alpha02.txt b/lifecycle/lifecycle-viewmodel/api/2.2.0-alpha02.txt
index 1c69a2a..dff8f71 100644
--- a/lifecycle/lifecycle-viewmodel/api/2.2.0-alpha02.txt
+++ b/lifecycle/lifecycle-viewmodel/api/2.2.0-alpha02.txt
@@ -12,6 +12,7 @@
   }
 
   public class ViewModelProvider {
+    ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner);
     ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner, androidx.lifecycle.ViewModelProvider.Factory);
     ctor public ViewModelProvider(androidx.lifecycle.ViewModelStore, androidx.lifecycle.ViewModelProvider.Factory);
     method @MainThread public <T extends androidx.lifecycle.ViewModel> T get(Class<T!>);
@@ -38,6 +39,7 @@
   }
 
   public interface ViewModelStoreOwner {
+    method public default androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
     method public androidx.lifecycle.ViewModelStore getViewModelStore();
   }
 
diff --git a/lifecycle/lifecycle-viewmodel/api/current.txt b/lifecycle/lifecycle-viewmodel/api/current.txt
index 1c69a2a..dff8f71 100644
--- a/lifecycle/lifecycle-viewmodel/api/current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/current.txt
@@ -12,6 +12,7 @@
   }
 
   public class ViewModelProvider {
+    ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner);
     ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner, androidx.lifecycle.ViewModelProvider.Factory);
     ctor public ViewModelProvider(androidx.lifecycle.ViewModelStore, androidx.lifecycle.ViewModelProvider.Factory);
     method @MainThread public <T extends androidx.lifecycle.ViewModel> T get(Class<T!>);
@@ -38,6 +39,7 @@
   }
 
   public interface ViewModelStoreOwner {
+    method public default androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
     method public androidx.lifecycle.ViewModelStore getViewModelStore();
   }
 
diff --git a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.java b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.java
index 56d9f1b..0fd77ff 100644
--- a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.java
+++ b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.java
@@ -82,6 +82,20 @@
     private final ViewModelStore mViewModelStore;
 
     /**
+     * Creates {@code ViewModelProvider}, which will create {@code ViewModels} via the
+     * {@link ViewModelStoreOwner#getDefaultViewModelProviderFactory() default factory}
+     * and retain them in a store of the given {@code ViewModelStoreOwner}.
+     *
+     * @param owner a {@code ViewModelStoreOwner} whose {@link ViewModelStore} will be used to
+     * retain {@code ViewModels}. The
+     * {@link ViewModelStoreOwner#getDefaultViewModelProviderFactory() default factory}
+     * will be used to create {@code ViewModels}.
+     */
+    public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
+        this(owner.getViewModelStore(), owner.getDefaultViewModelProviderFactory());
+    }
+
+    /**
      * Creates {@code ViewModelProvider}, which will create {@code ViewModels} via the given
      * {@code Factory} and retain them in a store of the given {@code ViewModelStoreOwner}.
      *
@@ -172,6 +186,21 @@
      */
     public static class NewInstanceFactory implements Factory {
 
+        private static NewInstanceFactory sInstance;
+
+        /**
+         * Retrieve a singleton instance of NewInstanceFactory.
+         *
+         * @return A valid {@link NewInstanceFactory}
+         */
+        @NonNull
+        static NewInstanceFactory getInstance() {
+            if (sInstance == null) {
+                sInstance = new NewInstanceFactory();
+            }
+            return sInstance;
+        }
+
         @SuppressWarnings("ClassNewInstance")
         @NonNull
         @Override
diff --git a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelStoreOwner.java b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelStoreOwner.java
index d9bec9f..a92ecdb 100644
--- a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelStoreOwner.java
+++ b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelStoreOwner.java
@@ -34,4 +34,16 @@
      */
     @NonNull
     ViewModelStore getViewModelStore();
+
+    /**
+     * Returns the default {@link ViewModelProvider.Factory} that should be
+     * used when no custom {@code Factory} is provided to the
+     * {@link ViewModelProvider} constructors.
+     *
+     * @return a {@code ViewModelProvider.Factory}
+     */
+    @NonNull
+    default ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
+        return ViewModelProvider.NewInstanceFactory.getInstance();
+    }
 }
diff --git a/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.java b/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.java
index dd9470f..7c86e00 100644
--- a/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.java
+++ b/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.java
@@ -85,6 +85,44 @@
     }
 
     @Test
+    public void testDefaultFactory() {
+        final ViewModelStore store = new ViewModelStore();
+        ViewModelStoreOwner owner = new ViewModelStoreOwner() {
+            @NonNull
+            @Override
+            public ViewModelStore getViewModelStore() {
+                return store;
+            }
+        };
+        ViewModelProvider provider = new ViewModelProvider(owner);
+        ViewModel1 viewModel = provider.get(ViewModel1.class);
+        assertThat(viewModel, is(provider.get(ViewModel1.class)));
+    }
+
+    @Test
+    public void testCustomDefaultFactory() {
+        final ViewModelStore store = new ViewModelStore();
+        final CountingFactory factory = new CountingFactory();
+        ViewModelStoreOwner owner = new ViewModelStoreOwner() {
+            @NonNull
+            @Override
+            public ViewModelStore getViewModelStore() {
+                return store;
+            }
+
+            @NonNull
+            @Override
+            public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
+                return factory;
+            }
+        };
+        ViewModelProvider provider = new ViewModelProvider(owner);
+        ViewModel1 viewModel = provider.get(ViewModel1.class);
+        assertThat(viewModel, is(provider.get(ViewModel1.class)));
+        assertThat(factory.mCalled, is(1));
+    }
+
+    @Test
     public void testKeyedFactory() {
         final ViewModelStore store = new ViewModelStore();
         ViewModelStoreOwner owner = new ViewModelStoreOwner() {
@@ -118,4 +156,15 @@
 
     public static class ViewModel2 extends ViewModel {
     }
+
+    public static class CountingFactory extends NewInstanceFactory {
+        int mCalled = 0;
+
+        @Override
+        @NonNull
+        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
+            mCalled++;
+            return super.create(modelClass);
+        }
+    }
 }