xref: /aosp_15_r20/external/dagger2/javatests/dagger/hilt/android/ViewModelScopedTest.java (revision f585d8a307d0621d6060bd7e80091fdcbf94fe27)
1 /*
2  * Copyright (C) 2020 The Dagger Authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package dagger.hilt.android;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import android.os.Build;
22 import android.os.Bundle;
23 import androidx.fragment.app.Fragment;
24 import androidx.fragment.app.FragmentActivity;
25 import androidx.annotation.Nullable;
26 import androidx.lifecycle.ViewModel;
27 import androidx.lifecycle.ViewModelProvider;
28 import androidx.test.core.app.ActivityScenario;
29 import androidx.test.ext.junit.runners.AndroidJUnit4;
30 import dagger.hilt.android.lifecycle.HiltViewModel;
31 import dagger.hilt.android.scopes.ViewModelScoped;
32 import dagger.hilt.android.testing.HiltAndroidRule;
33 import dagger.hilt.android.testing.HiltAndroidTest;
34 import dagger.hilt.android.testing.HiltTestApplication;
35 import javax.inject.Inject;
36 import org.junit.Rule;
37 import org.junit.Test;
38 import org.junit.runner.RunWith;
39 import org.robolectric.annotation.Config;
40 
41 @HiltAndroidTest
42 @RunWith(AndroidJUnit4.class)
43 // Robolectric requires Java9 to run API 29 and above, so use API 28 instead
44 @Config(sdk = Build.VERSION_CODES.P, application = HiltTestApplication.class)
45 public class ViewModelScopedTest {
46 
47   @Rule public final HiltAndroidRule rule = new HiltAndroidRule(this);
48 
49   @Test
testViewModelScopeInFragment()50   public void testViewModelScopeInFragment() {
51     try (ActivityScenario<TestActivity> scenario = ActivityScenario.launch(TestActivity.class)) {
52       scenario.onActivity(
53           activity -> {
54             TestFragment fragment =
55                 (TestFragment) activity.getSupportFragmentManager().findFragmentByTag("tag");
56             // Check that the scoped bar is the same instance within the same view model.
57             assertThat(fragment.vm1.one.bar).isEqualTo(fragment.vm1.two.bar);
58             assertThat(fragment.vm2.one.bar).isEqualTo(fragment.vm2.two.bar);
59 
60             // Check that the keyed viewmodels are separate by checking that the bar instances
61             // are different, and hence have different components.
62             assertThat(fragment.vm1.one.bar).isNotEqualTo(fragment.vm2.one.bar);
63 
64             activity.getSupportFragmentManager().beginTransaction().remove(fragment).commitNow();
65 
66             assertThat(fragment.vm1.cleared).isTrue();
67             assertThat(fragment.vm2.cleared).isTrue();
68           });
69     }
70   }
71 
72   @AndroidEntryPoint(FragmentActivity.class)
73   public static class TestActivity extends Hilt_ViewModelScopedTest_TestActivity {
74 
75     @Override
onCreate(@ullable Bundle savedInstanceState)76     protected void onCreate(@Nullable Bundle savedInstanceState) {
77       super.onCreate(savedInstanceState);
78       if (savedInstanceState == null) {
79         Fragment f =
80             getSupportFragmentManager()
81                 .getFragmentFactory()
82                 .instantiate(TestFragment.class.getClassLoader(), TestFragment.class.getName());
83         getSupportFragmentManager().beginTransaction().add(0, f, "tag").commitNow();
84       }
85     }
86   }
87 
88   @AndroidEntryPoint(Fragment.class)
89   public static class TestFragment extends Hilt_ViewModelScopedTest_TestFragment {
90     MyViewModel vm1;
91     MyViewModel vm2;
92 
93     @Override
onCreate(@ullable Bundle bundle)94     public void onCreate(@Nullable Bundle bundle) {
95       super.onCreate(bundle);
96       vm1 = new ViewModelProvider(this).get("foo", MyViewModel.class);
97       vm2 = new ViewModelProvider(this).get("bar", MyViewModel.class);
98     }
99   }
100 
101   @HiltViewModel
102   static class MyViewModel extends ViewModel {
103 
104     final DependsOnBarOne one;
105     final DependsOnBarTwo two;
106     boolean cleared = false;
107 
108     @Inject
MyViewModel(DependsOnBarOne one, DependsOnBarTwo two, ViewModelLifecycle lifecycle)109     MyViewModel(DependsOnBarOne one, DependsOnBarTwo two, ViewModelLifecycle lifecycle) {
110       this.one = one;
111       this.two = two;
112       lifecycle.addOnClearedListener(() -> cleared = true);
113     }
114   }
115 
116   @ViewModelScoped
117   static class Bar {
118     @Inject
Bar()119     Bar() {}
120   }
121 
122   static class DependsOnBarOne {
123     final Bar bar;
124 
125     @Inject
DependsOnBarOne(Bar bar)126     DependsOnBarOne(Bar bar) {
127       this.bar = bar;
128     }
129   }
130 
131   static class DependsOnBarTwo {
132     final Bar bar;
133 
134     @Inject
DependsOnBarTwo(Bar bar)135     DependsOnBarTwo(Bar bar) {
136       this.bar = bar;
137     }
138   }
139 }
140