Skip to content

Commit

Permalink
Provide SavedStateHandle binding from ActivityRetainedComponent.
Browse files Browse the repository at this point in the history
RELNOTES=n/a
PiperOrigin-RevId: 577983612
  • Loading branch information
wanyingd1996 authored and Dagger Team committed Oct 30, 2023
1 parent 6fe4a23 commit 1cac33b
Show file tree
Hide file tree
Showing 21 changed files with 545 additions and 6 deletions.
2 changes: 2 additions & 0 deletions java/dagger/hilt/android/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,11 @@ gen_maven_artifact(
"//java/dagger/hilt/android/internal/lifecycle",
"//java/dagger/hilt/android/internal/managers",
"//java/dagger/hilt/android/internal/managers:component_supplier",
"//java/dagger/hilt/android/internal/managers:saved_state_handle_holder",
"//java/dagger/hilt/android/internal/migration:has_custom_inject",
"//java/dagger/hilt/android/internal/migration:injected_by_hilt",
"//java/dagger/hilt/android/internal/modules",
"//java/dagger/hilt/android/lifecycle:activity_retained_saved_state",
"//java/dagger/hilt/android/lifecycle:hilt_view_model",
"//java/dagger/hilt/android/lifecycle:hilt_view_model_extensions",
"//java/dagger/hilt/android/lifecycle:package_info",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@

package dagger.hilt.android.internal.builders;

import dagger.BindsInstance;
import dagger.hilt.DefineComponent;
import dagger.hilt.android.components.ActivityRetainedComponent;
import dagger.hilt.android.internal.managers.SavedStateHandleHolder;

/** Interface for creating a {@link ActivityRetainedComponent}. */
@DefineComponent.Builder
public interface ActivityRetainedComponentBuilder {

ActivityRetainedComponentBuilder savedStateHandleHolder(
@BindsInstance SavedStateHandleHolder savedStateHandleHolder);

ActivityRetainedComponent build();
}
1 change: 1 addition & 0 deletions java/dagger/hilt/android/internal/builders/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ android_library(
"//java/dagger/hilt:define_component",
"//java/dagger/hilt/android:view_model_lifecycle",
"//java/dagger/hilt/android/components",
"//java/dagger/hilt/android/internal/managers:saved_state_handle_holder",
"@maven//:androidx_activity_activity",
"@maven//:androidx_fragment_fragment",
"@maven//:androidx_lifecycle_lifecycle_common",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ public Object generatedComponent() {
return component;
}

public final SavedStateHandleHolder getSavedStateHandleHolder() {
// This will only be used on base activity that extends ComponentActivity.
return ((ActivityRetainedComponentManager) activityRetainedComponentManager)
.getSavedStateHandleHolder();
}

protected Object createComponent() {
if (!(activity.getApplication() instanceof GeneratedComponentManager)) {
throw new IllegalStateException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelStoreOwner;
import androidx.lifecycle.viewmodel.CreationExtras;
import dagger.Module;
import dagger.Provides;
import dagger.hilt.EntryPoint;
Expand Down Expand Up @@ -57,15 +58,22 @@ public interface ActivityRetainedLifecycleEntryPoint {

static final class ActivityRetainedComponentViewModel extends ViewModel {
private final ActivityRetainedComponent component;
private final SavedStateHandleHolder savedStateHandleHolder;

ActivityRetainedComponentViewModel(ActivityRetainedComponent component) {
ActivityRetainedComponentViewModel(
ActivityRetainedComponent component, SavedStateHandleHolder savedStateHandleHolder) {
this.component = component;
this.savedStateHandleHolder = savedStateHandleHolder;
}

ActivityRetainedComponent getComponent() {
return component;
}

SavedStateHandleHolder getSavedStateHandleHolder() {
return savedStateHandleHolder;
}

@Override
protected void onCleared() {
super.onCleared();
Expand Down Expand Up @@ -95,13 +103,17 @@ private ViewModelProvider getViewModelProvider(
@NonNull
@Override
@SuppressWarnings("unchecked")
public <T extends ViewModel> T create(@NonNull Class<T> aClass) {
public <T extends ViewModel> T create(
@NonNull Class<T> aClass, CreationExtras creationExtras) {
SavedStateHandleHolder savedStateHandleHolder =
new SavedStateHandleHolder(creationExtras);
ActivityRetainedComponent component =
EntryPointAccessors.fromApplication(
context, ActivityRetainedComponentBuilderEntryPoint.class)
context, ActivityRetainedComponentBuilderEntryPoint.class)
.retainedComponentBuilder()
.savedStateHandleHolder(savedStateHandleHolder)
.build();
return (T) new ActivityRetainedComponentViewModel(component);
return (T) new ActivityRetainedComponentViewModel(component, savedStateHandleHolder);
}
});
}
Expand All @@ -118,6 +130,12 @@ public ActivityRetainedComponent generatedComponent() {
return component;
}

public SavedStateHandleHolder getSavedStateHandleHolder() {
return getViewModelProvider(viewModelStoreOwner, context)
.get(ActivityRetainedComponentViewModel.class)
.getSavedStateHandleHolder();
}

private ActivityRetainedComponent createComponent() {
return getViewModelProvider(viewModelStoreOwner, context)
.get(ActivityRetainedComponentViewModel.class)
Expand Down
19 changes: 19 additions & 0 deletions java/dagger/hilt/android/internal/managers/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@ android_library(
"ApplicationComponentManager.java",
"BroadcastReceiverComponentManager.java",
"FragmentComponentManager.java",
"SavedStateHandleModule.java",
"ServiceComponentManager.java",
"ViewComponentManager.java",
],
exports = [":saved_state_handle_holder"],
deps = [
":component_supplier",
":saved_state_handle_holder",
"//:dagger_with_compiler",
"//java/dagger/hilt:entry_point",
"//java/dagger/hilt:install_in",
Expand All @@ -44,6 +47,7 @@ android_library(
"//java/dagger/hilt/android/internal",
"//java/dagger/hilt/android/internal/builders",
"//java/dagger/hilt/android/internal/lifecycle",
"//java/dagger/hilt/android/lifecycle:activity_retained_saved_state",
"//java/dagger/hilt/android/scopes",
"//java/dagger/hilt/internal:component_manager",
"//java/dagger/hilt/internal:preconditions",
Expand All @@ -56,6 +60,21 @@ android_library(
],
)

android_library(
name = "saved_state_handle_holder",
srcs = ["SavedStateHandleHolder.java"],
deps = [
"//java/dagger/hilt/android/internal",
"//java/dagger/hilt/internal:preconditions",
"@maven//:androidx_activity_activity",
"@maven//:androidx_annotation_annotation",
"@maven//:androidx_fragment_fragment",
"@maven//:androidx_lifecycle_lifecycle_common",
"@maven//:androidx_lifecycle_lifecycle_viewmodel",
"@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
],
)

filegroup(
name = "srcs_filegroup",
srcs = glob(["*"]),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (C) 2023 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dagger.hilt.android.internal.managers;

import static dagger.hilt.internal.Preconditions.checkNotNull;
import static dagger.hilt.internal.Preconditions.checkState;

import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.SavedStateHandleSupport;
import androidx.lifecycle.viewmodel.CreationExtras;
import androidx.lifecycle.viewmodel.MutableCreationExtras;
import dagger.hilt.android.internal.ThreadUtil;

/** Implementation for SavedStateHandleHolder. */
public final class SavedStateHandleHolder {
private CreationExtras extras;
private SavedStateHandle handle;
private final boolean nonComponentActivity;

SavedStateHandleHolder(@Nullable CreationExtras extras) {
nonComponentActivity = (extras == null);
this.extras = extras;
}

SavedStateHandle getSavedStateHandle() {
ThreadUtil.ensureMainThread();
checkState(
!nonComponentActivity,
"Activity that does not extend ComponentActivity cannot use SavedStateHandle");
if (handle != null) {
return handle;
}
checkNotNull(
extras,
"The first access to SavedStateHandle should happen between super.onCreate() and"
+ " super.onDestroy()");
// Clean up default args, since those are unused and we don't want to duplicate those for each
// SavedStateHandle
MutableCreationExtras mutableExtras = new MutableCreationExtras(extras);
mutableExtras.set(SavedStateHandleSupport.DEFAULT_ARGS_KEY, Bundle.EMPTY);
extras = mutableExtras;
handle = SavedStateHandleSupport.createSavedStateHandle(extras);

extras = null;
return handle;
}

public void clear() {
extras = null;
}

public void setExtras(CreationExtras extras) {
if (handle != null) {
// If handle is already created, we don't need to store CreationExtras.
return;
}
this.extras = extras;
}

public boolean isInvalid() {
return handle == null && extras == null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2023 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dagger.hilt.android.internal.managers;

import androidx.lifecycle.SavedStateHandle;
import dagger.Module;
import dagger.Provides;
import dagger.hilt.InstallIn;
import dagger.hilt.android.components.ActivityRetainedComponent;
import dagger.hilt.android.lifecycle.ActivityRetainedSavedState;
import dagger.hilt.android.scopes.ActivityRetainedScoped;

/** Module providing SavedStateHandle from ActivityRetainedComponent. */
@Module
@InstallIn(ActivityRetainedComponent.class)
abstract class SavedStateHandleModule {
@ActivityRetainedSavedState
@ActivityRetainedScoped
@Provides
static SavedStateHandle provideSavedStateHandle(SavedStateHandleHolder savedStateHandleHolder) {
return savedStateHandleHolder.getSavedStateHandle();
}
}
26 changes: 26 additions & 0 deletions java/dagger/hilt/android/lifecycle/ActivityRetainedSavedState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2023 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dagger.hilt.android.lifecycle;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import javax.inject.Qualifier;

/** Qualifies a binding that belongs to ActivityRetainedComponent. */
@Qualifier
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
public @interface ActivityRetainedSavedState {}
6 changes: 6 additions & 0 deletions java/dagger/hilt/android/lifecycle/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ android_library(
],
)

android_library(
name = "activity_retained_saved_state",
srcs = ["ActivityRetainedSavedState.java"],
deps = ["//third_party/java/jsr330_inject"],
)

compat_kt_android_library(
name = "hilt_view_model_extensions",
srcs = ["HiltViewModelExtensions.kt"],
Expand Down
1 change: 1 addition & 0 deletions java/dagger/hilt/android/processor/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ gen_maven_artifact(
"//java/dagger/hilt/processor/internal:component_names",
"//java/dagger/hilt/processor/internal:components",
"//java/dagger/hilt/processor/internal:hilt_processing_env_configs",
"//java/dagger/hilt/processor/internal:method_signature",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/hilt/processor/internal/aggregateddeps:component_dependencies",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ public final class AndroidClassNames {
get("dagger.hilt.android.internal.managers", "ServiceComponentManager");
public static final ClassName VIEW_COMPONENT_MANAGER =
get("dagger.hilt.android.internal.managers", "ViewComponentManager");
public static final ClassName SAVED_STATE_HANDLE_ENTRY_POINTS =
get("dagger.hilt.android.internal.managers", "SavedStateHandleEntryPoints");
public static final ClassName SAVED_STATE_HANDLE_HOLDER =
get("dagger.hilt.android.internal.managers", "SavedStateHandleHolder");

public static final ClassName HAS_CUSTOM_INJECT =
get("dagger.hilt.android.internal.migration", "HasCustomInject");
Expand All @@ -125,9 +129,13 @@ public final class AndroidClassNames {
get("androidx.lifecycle", "ViewModelProvider", "Factory");
public static final ClassName SAVED_STATE_HANDLE =
get("androidx.lifecycle", "SavedStateHandle");

public static final ClassName DEFAULT_LIFECYCLE_OBSERVER =
get("androidx.lifecycle", "DefaultLifecycleObserver");
public static final ClassName LIFECYCLE_OWNER = get("androidx.lifecycle", "LifecycleOwner");
public static final ClassName ON_CONTEXT_AVAILABLE_LISTENER =
get("androidx.activity.contextaware", "OnContextAvailableListener");
public static final ClassName UI_THREAD = get("androidx.annotation", "UiThread");

public static final ClassName INJECT_VIA_ON_CONTEXT_AVAILABLE_LISTENER =
get("dagger.hilt.android", "InjectViaOnContextAvailableListener");

Expand Down
Loading

0 comments on commit 1cac33b

Please sign in to comment.