Skip to content

Commit 1cac33b

Browse files
wanyingd1996Dagger Team
authored andcommitted
Provide SavedStateHandle binding from ActivityRetainedComponent.
RELNOTES=n/a PiperOrigin-RevId: 577983612
1 parent 6fe4a23 commit 1cac33b

File tree

21 files changed

+545
-6
lines changed

21 files changed

+545
-6
lines changed

java/dagger/hilt/android/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,11 @@ gen_maven_artifact(
194194
"//java/dagger/hilt/android/internal/lifecycle",
195195
"//java/dagger/hilt/android/internal/managers",
196196
"//java/dagger/hilt/android/internal/managers:component_supplier",
197+
"//java/dagger/hilt/android/internal/managers:saved_state_handle_holder",
197198
"//java/dagger/hilt/android/internal/migration:has_custom_inject",
198199
"//java/dagger/hilt/android/internal/migration:injected_by_hilt",
199200
"//java/dagger/hilt/android/internal/modules",
201+
"//java/dagger/hilt/android/lifecycle:activity_retained_saved_state",
200202
"//java/dagger/hilt/android/lifecycle:hilt_view_model",
201203
"//java/dagger/hilt/android/lifecycle:hilt_view_model_extensions",
202204
"//java/dagger/hilt/android/lifecycle:package_info",

java/dagger/hilt/android/internal/builders/ActivityRetainedComponentBuilder.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,17 @@
1616

1717
package dagger.hilt.android.internal.builders;
1818

19+
import dagger.BindsInstance;
1920
import dagger.hilt.DefineComponent;
2021
import dagger.hilt.android.components.ActivityRetainedComponent;
22+
import dagger.hilt.android.internal.managers.SavedStateHandleHolder;
2123

2224
/** Interface for creating a {@link ActivityRetainedComponent}. */
2325
@DefineComponent.Builder
2426
public interface ActivityRetainedComponentBuilder {
27+
28+
ActivityRetainedComponentBuilder savedStateHandleHolder(
29+
@BindsInstance SavedStateHandleHolder savedStateHandleHolder);
30+
2531
ActivityRetainedComponent build();
2632
}

java/dagger/hilt/android/internal/builders/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ android_library(
2525
"//java/dagger/hilt:define_component",
2626
"//java/dagger/hilt/android:view_model_lifecycle",
2727
"//java/dagger/hilt/android/components",
28+
"//java/dagger/hilt/android/internal/managers:saved_state_handle_holder",
2829
"@maven//:androidx_activity_activity",
2930
"@maven//:androidx_fragment_fragment",
3031
"@maven//:androidx_lifecycle_lifecycle_common",

java/dagger/hilt/android/internal/managers/ActivityComponentManager.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ public Object generatedComponent() {
7070
return component;
7171
}
7272

73+
public final SavedStateHandleHolder getSavedStateHandleHolder() {
74+
// This will only be used on base activity that extends ComponentActivity.
75+
return ((ActivityRetainedComponentManager) activityRetainedComponentManager)
76+
.getSavedStateHandleHolder();
77+
}
78+
7379
protected Object createComponent() {
7480
if (!(activity.getApplication() instanceof GeneratedComponentManager)) {
7581
throw new IllegalStateException(

java/dagger/hilt/android/internal/managers/ActivityRetainedComponentManager.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import androidx.lifecycle.ViewModel;
2424
import androidx.lifecycle.ViewModelProvider;
2525
import androidx.lifecycle.ViewModelStoreOwner;
26+
import androidx.lifecycle.viewmodel.CreationExtras;
2627
import dagger.Module;
2728
import dagger.Provides;
2829
import dagger.hilt.EntryPoint;
@@ -57,15 +58,22 @@ public interface ActivityRetainedLifecycleEntryPoint {
5758

5859
static final class ActivityRetainedComponentViewModel extends ViewModel {
5960
private final ActivityRetainedComponent component;
61+
private final SavedStateHandleHolder savedStateHandleHolder;
6062

61-
ActivityRetainedComponentViewModel(ActivityRetainedComponent component) {
63+
ActivityRetainedComponentViewModel(
64+
ActivityRetainedComponent component, SavedStateHandleHolder savedStateHandleHolder) {
6265
this.component = component;
66+
this.savedStateHandleHolder = savedStateHandleHolder;
6367
}
6468

6569
ActivityRetainedComponent getComponent() {
6670
return component;
6771
}
6872

73+
SavedStateHandleHolder getSavedStateHandleHolder() {
74+
return savedStateHandleHolder;
75+
}
76+
6977
@Override
7078
protected void onCleared() {
7179
super.onCleared();
@@ -95,13 +103,17 @@ private ViewModelProvider getViewModelProvider(
95103
@NonNull
96104
@Override
97105
@SuppressWarnings("unchecked")
98-
public <T extends ViewModel> T create(@NonNull Class<T> aClass) {
106+
public <T extends ViewModel> T create(
107+
@NonNull Class<T> aClass, CreationExtras creationExtras) {
108+
SavedStateHandleHolder savedStateHandleHolder =
109+
new SavedStateHandleHolder(creationExtras);
99110
ActivityRetainedComponent component =
100111
EntryPointAccessors.fromApplication(
101-
context, ActivityRetainedComponentBuilderEntryPoint.class)
112+
context, ActivityRetainedComponentBuilderEntryPoint.class)
102113
.retainedComponentBuilder()
114+
.savedStateHandleHolder(savedStateHandleHolder)
103115
.build();
104-
return (T) new ActivityRetainedComponentViewModel(component);
116+
return (T) new ActivityRetainedComponentViewModel(component, savedStateHandleHolder);
105117
}
106118
});
107119
}
@@ -118,6 +130,12 @@ public ActivityRetainedComponent generatedComponent() {
118130
return component;
119131
}
120132

133+
public SavedStateHandleHolder getSavedStateHandleHolder() {
134+
return getViewModelProvider(viewModelStoreOwner, context)
135+
.get(ActivityRetainedComponentViewModel.class)
136+
.getSavedStateHandleHolder();
137+
}
138+
121139
private ActivityRetainedComponent createComponent() {
122140
return getViewModelProvider(viewModelStoreOwner, context)
123141
.get(ActivityRetainedComponentViewModel.class)

java/dagger/hilt/android/internal/managers/BUILD

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,14 @@ android_library(
3030
"ApplicationComponentManager.java",
3131
"BroadcastReceiverComponentManager.java",
3232
"FragmentComponentManager.java",
33+
"SavedStateHandleModule.java",
3334
"ServiceComponentManager.java",
3435
"ViewComponentManager.java",
3536
],
37+
exports = [":saved_state_handle_holder"],
3638
deps = [
3739
":component_supplier",
40+
":saved_state_handle_holder",
3841
"//:dagger_with_compiler",
3942
"//java/dagger/hilt:entry_point",
4043
"//java/dagger/hilt:install_in",
@@ -44,6 +47,7 @@ android_library(
4447
"//java/dagger/hilt/android/internal",
4548
"//java/dagger/hilt/android/internal/builders",
4649
"//java/dagger/hilt/android/internal/lifecycle",
50+
"//java/dagger/hilt/android/lifecycle:activity_retained_saved_state",
4751
"//java/dagger/hilt/android/scopes",
4852
"//java/dagger/hilt/internal:component_manager",
4953
"//java/dagger/hilt/internal:preconditions",
@@ -56,6 +60,21 @@ android_library(
5660
],
5761
)
5862

63+
android_library(
64+
name = "saved_state_handle_holder",
65+
srcs = ["SavedStateHandleHolder.java"],
66+
deps = [
67+
"//java/dagger/hilt/android/internal",
68+
"//java/dagger/hilt/internal:preconditions",
69+
"@maven//:androidx_activity_activity",
70+
"@maven//:androidx_annotation_annotation",
71+
"@maven//:androidx_fragment_fragment",
72+
"@maven//:androidx_lifecycle_lifecycle_common",
73+
"@maven//:androidx_lifecycle_lifecycle_viewmodel",
74+
"@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
75+
],
76+
)
77+
5978
filegroup(
6079
name = "srcs_filegroup",
6180
srcs = glob(["*"]),
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (C) 2023 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.internal.managers;
18+
19+
import static dagger.hilt.internal.Preconditions.checkNotNull;
20+
import static dagger.hilt.internal.Preconditions.checkState;
21+
22+
import android.os.Bundle;
23+
import androidx.annotation.Nullable;
24+
import androidx.lifecycle.SavedStateHandle;
25+
import androidx.lifecycle.SavedStateHandleSupport;
26+
import androidx.lifecycle.viewmodel.CreationExtras;
27+
import androidx.lifecycle.viewmodel.MutableCreationExtras;
28+
import dagger.hilt.android.internal.ThreadUtil;
29+
30+
/** Implementation for SavedStateHandleHolder. */
31+
public final class SavedStateHandleHolder {
32+
private CreationExtras extras;
33+
private SavedStateHandle handle;
34+
private final boolean nonComponentActivity;
35+
36+
SavedStateHandleHolder(@Nullable CreationExtras extras) {
37+
nonComponentActivity = (extras == null);
38+
this.extras = extras;
39+
}
40+
41+
SavedStateHandle getSavedStateHandle() {
42+
ThreadUtil.ensureMainThread();
43+
checkState(
44+
!nonComponentActivity,
45+
"Activity that does not extend ComponentActivity cannot use SavedStateHandle");
46+
if (handle != null) {
47+
return handle;
48+
}
49+
checkNotNull(
50+
extras,
51+
"The first access to SavedStateHandle should happen between super.onCreate() and"
52+
+ " super.onDestroy()");
53+
// Clean up default args, since those are unused and we don't want to duplicate those for each
54+
// SavedStateHandle
55+
MutableCreationExtras mutableExtras = new MutableCreationExtras(extras);
56+
mutableExtras.set(SavedStateHandleSupport.DEFAULT_ARGS_KEY, Bundle.EMPTY);
57+
extras = mutableExtras;
58+
handle = SavedStateHandleSupport.createSavedStateHandle(extras);
59+
60+
extras = null;
61+
return handle;
62+
}
63+
64+
public void clear() {
65+
extras = null;
66+
}
67+
68+
public void setExtras(CreationExtras extras) {
69+
if (handle != null) {
70+
// If handle is already created, we don't need to store CreationExtras.
71+
return;
72+
}
73+
this.extras = extras;
74+
}
75+
76+
public boolean isInvalid() {
77+
return handle == null && extras == null;
78+
}
79+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (C) 2023 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.internal.managers;
18+
19+
import androidx.lifecycle.SavedStateHandle;
20+
import dagger.Module;
21+
import dagger.Provides;
22+
import dagger.hilt.InstallIn;
23+
import dagger.hilt.android.components.ActivityRetainedComponent;
24+
import dagger.hilt.android.lifecycle.ActivityRetainedSavedState;
25+
import dagger.hilt.android.scopes.ActivityRetainedScoped;
26+
27+
/** Module providing SavedStateHandle from ActivityRetainedComponent. */
28+
@Module
29+
@InstallIn(ActivityRetainedComponent.class)
30+
abstract class SavedStateHandleModule {
31+
@ActivityRetainedSavedState
32+
@ActivityRetainedScoped
33+
@Provides
34+
static SavedStateHandle provideSavedStateHandle(SavedStateHandleHolder savedStateHandleHolder) {
35+
return savedStateHandleHolder.getSavedStateHandle();
36+
}
37+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright (C) 2023 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.lifecycle;
18+
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Target;
21+
import javax.inject.Qualifier;
22+
23+
/** Qualifies a binding that belongs to ActivityRetainedComponent. */
24+
@Qualifier
25+
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
26+
public @interface ActivityRetainedSavedState {}

java/dagger/hilt/android/lifecycle/BUILD

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ android_library(
5656
],
5757
)
5858

59+
android_library(
60+
name = "activity_retained_saved_state",
61+
srcs = ["ActivityRetainedSavedState.java"],
62+
deps = ["//third_party/java/jsr330_inject"],
63+
)
64+
5965
compat_kt_android_library(
6066
name = "hilt_view_model_extensions",
6167
srcs = ["HiltViewModelExtensions.kt"],

0 commit comments

Comments
 (0)