Skip to content

Commit

Permalink
Support an onCleared callback in the ActivityRetainedComponent.
Browse files Browse the repository at this point in the history
This adds a default binding to the ActivityRetainedComponent
allowing users to register onCleared listeners that will be
invoked when the activity retained component and its instances
will be destroyed.

RELNOTES=Add support for receiving a callback for when the activity retained component will no longer be used and destroyed.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=326057949
  • Loading branch information
danysantiago authored and cgdecker committed Aug 12, 2020
1 parent d77821e commit 6300d02
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 2 deletions.
1 change: 1 addition & 0 deletions java/dagger/hilt/BUILD
Expand Up @@ -118,6 +118,7 @@ filegroup(
"//java/dagger/hilt/android:srcs_filegroup",
"//java/dagger/hilt/android/components:srcs_filegroup",
"//java/dagger/hilt/android/qualifiers:srcs_filegroup",
"//java/dagger/hilt/android/internal:srcs_filegroup",
"//java/dagger/hilt/android/internal/builders:srcs_filegroup",
"//java/dagger/hilt/android/internal/lifecycle:srcs_filegroup",
"//java/dagger/hilt/android/internal/managers:srcs_filegroup",
Expand Down
61 changes: 61 additions & 0 deletions java/dagger/hilt/android/ActivityRetainedLifecycle.java
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2020 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;

import android.app.Activity;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;

/**
* A <code>ActivityRetainedLifecycle</code> class is associated with the lifecycle of the {@link
* dagger.hilt.android.components.ActivityRetainedComponent}.
*/
public interface ActivityRetainedLifecycle {

/**
* Adds a new {@link OnClearedListener} for receiving a callback when the activity retained
* instances will no longer be needed and destroyed.
*
* @param listener The listener that should be added.
*/
@MainThread
void addOnClearedListener(@NonNull OnClearedListener listener);

/**
* Removes a {@link OnClearedListener} previously added via {@link
* #addOnClearedListener(OnClearedListener)}.
*
* @param listener The listener that should be removed.
*/
@MainThread
void removeOnClearedListener(@NonNull OnClearedListener listener);

/**
* Listener for receiving a callback for when the {@link
* dagger.hilt.android.components.ActivityRetainedComponent} will no longer be used and destroyed.
*/
interface OnClearedListener {

/**
* Called when the activity retained instances will no longer be used and destroyed.
*
* <p>Specifically this will be invoked during {@link Activity#onDestroy()} when {@link
* Activity#isChangingConfigurations} is false.
*/
void onCleared();
}
}
11 changes: 11 additions & 0 deletions java/dagger/hilt/android/BUILD
Expand Up @@ -88,6 +88,15 @@ android_library(
],
)

android_library(
name = "activity_retained_lifecycle",
srcs = ["ActivityRetainedLifecycle.java"],
deps = [
":package_info",
"@maven//:androidx_annotation_annotation",
],
)

android_library(
name = "artifact-lib",
tags = ["maven_coordinates=com.google.dagger:hilt-android:" + POM_VERSION_ALPHA],
Expand Down Expand Up @@ -126,11 +135,13 @@ gen_maven_artifact(
"//java/dagger/hilt:generates_root_input",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt:package_info",
"//java/dagger/hilt/android:activity_retained_lifecycle",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android:hilt_android_app",
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/components",
"//java/dagger/hilt/android/components:package_info",
"//java/dagger/hilt/android/internal",
"//java/dagger/hilt/android/internal/builders",
"//java/dagger/hilt/android/internal/lifecycle",
"//java/dagger/hilt/android/internal/managers",
Expand Down
28 changes: 28 additions & 0 deletions java/dagger/hilt/android/internal/BUILD
@@ -0,0 +1,28 @@
# Copyright (C) 2020 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.

# Description:
# Internal Hilt Android utitlies

package(default_visibility = ["//:src"])

android_library(
name = "internal",
srcs = ["ThreadUtil.java"],
)

filegroup(
name = "srcs_filegroup",
srcs = glob(["*"]),
)
42 changes: 42 additions & 0 deletions java/dagger/hilt/android/internal/ThreadUtil.java
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2020 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;

import android.os.Looper;

/** Thread utility methods. */
public final class ThreadUtil {

private static Thread mainThread;

private ThreadUtil() {}

/** Returns true if the current thread is the Main thread. */
public static boolean isMainThread() {
if (mainThread == null) {
mainThread = Looper.getMainLooper().getThread();
}
return Thread.currentThread() == mainThread;
}

/** Checks that the current thread is the Main thread. Otherwise throws an exception. */
public static void ensureMainThread() {
if (!isMainThread()) {
throw new IllegalStateException("Must be called on the Main thread.");
}
}
}
Expand Up @@ -21,24 +21,40 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.activity.ComponentActivity;
import dagger.Binds;
import dagger.Module;
import dagger.hilt.EntryPoint;
import dagger.hilt.EntryPoints;
import dagger.hilt.InstallIn;
import dagger.hilt.android.ActivityRetainedLifecycle;
import dagger.hilt.android.components.ActivityRetainedComponent;
import dagger.hilt.android.components.ApplicationComponent;
import dagger.hilt.android.internal.ThreadUtil;
import dagger.hilt.android.internal.builders.ActivityRetainedComponentBuilder;
import dagger.hilt.android.scopes.ActivityRetainedScoped;
import dagger.hilt.internal.GeneratedComponentManager;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject;

/** A manager for the creation of components that survives activity configuration changes. */
final class ActivityRetainedComponentManager
implements GeneratedComponentManager<ActivityRetainedComponent> {

/** Entry point for {@link ActivityRetainedComponentBuilder}. */
@EntryPoint
@InstallIn(ApplicationComponent.class)
public interface LifecycleComponentBuilderEntryPoint {
public interface ActivityRetainedComponentBuilderEntryPoint {
ActivityRetainedComponentBuilder retainedComponentBuilder();
}

/** Entry point for {@link Lifecycle}. */
@EntryPoint
@InstallIn(ActivityRetainedComponent.class)
public interface ActivityRetainedLifecycleEntryPoint {
ActivityRetainedLifecycle getActivityRetainedLifecycle();
}

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

Expand All @@ -49,6 +65,15 @@ static final class ActivityRetainedComponentViewModel extends ViewModel {
ActivityRetainedComponent getComponent() {
return component;
}

@Override
protected void onCleared() {
super.onCleared();
ActivityRetainedLifecycle lifecycle =
EntryPoints.get(component, ActivityRetainedLifecycleEntryPoint.class)
.getActivityRetainedLifecycle();
((ActivityRetainedComponentManager.Lifecycle) lifecycle).dispatchOnCleared();
}
}

private final ViewModelProvider viewModelProvider;
Expand All @@ -67,7 +92,8 @@ ActivityRetainedComponent getComponent() {
public <T extends ViewModel> T create(@NonNull Class<T> aClass) {
ActivityRetainedComponent component =
EntryPoints.get(
activity.getApplication(), LifecycleComponentBuilderEntryPoint.class)
activity.getApplication(),
ActivityRetainedComponentBuilderEntryPoint.class)
.retainedComponentBuilder()
.build();
return (T) new ActivityRetainedComponentViewModel(component);
Expand All @@ -91,4 +117,38 @@ private ActivityRetainedComponent createComponent() {
return viewModelProvider.get(ActivityRetainedComponentViewModel.class).getComponent();
}

/** The default implementation of {@link ActivityRetainedLifecycle}. */
@ActivityRetainedScoped
static final class Lifecycle implements ActivityRetainedLifecycle {

private final Set<OnClearedListener> listeners = new HashSet<>();

@Inject
Lifecycle() {}

@Override
public void addOnClearedListener(@NonNull OnClearedListener listener) {
ThreadUtil.ensureMainThread();
listeners.add(listener);
}

@Override
public void removeOnClearedListener(@NonNull OnClearedListener listener) {
ThreadUtil.ensureMainThread();
listeners.remove(listener);
}

void dispatchOnCleared() {
for (OnClearedListener listener : listeners) {
listener.onCleared();
}
}
}

@Module
@InstallIn(ActivityRetainedComponent.class)
abstract static class LifecycleModule {
@Binds
abstract ActivityRetainedLifecycle bind(Lifecycle impl);
}
}
4 changes: 4 additions & 0 deletions java/dagger/hilt/android/internal/managers/BUILD
Expand Up @@ -35,10 +35,14 @@ android_library(
],
deps = [
":component_supplier",
"//:dagger_with_compiler",
"//java/dagger/hilt:entry_point",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android:activity_retained_lifecycle",
"//java/dagger/hilt/android/components",
"//java/dagger/hilt/android/internal",
"//java/dagger/hilt/android/internal/builders",
"//java/dagger/hilt/android/scopes:activity_retained_scoped",
"//java/dagger/hilt/internal:component_manager",
"//java/dagger/hilt/internal:preconditions",
"@maven//:androidx_activity_activity",
Expand Down

0 comments on commit 6300d02

Please sign in to comment.