diff --git a/libs/WindowManager/Jetpack/src/androidx/window/util/AcceptOnceConsumer.java b/libs/WindowManager/Jetpack/src/androidx/window/util/AcceptOnceConsumer.java index 7624b693ac439..fe60037483c4b 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/util/AcceptOnceConsumer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/util/AcceptOnceConsumer.java @@ -27,9 +27,10 @@ import java.util.function.Consumer; */ public class AcceptOnceConsumer implements Consumer { private final Consumer mCallback; - private final DataProducer mProducer; + private final AcceptOnceProducerCallback mProducer; - public AcceptOnceConsumer(@NonNull DataProducer producer, @NonNull Consumer callback) { + public AcceptOnceConsumer(@NonNull AcceptOnceProducerCallback producer, + @NonNull Consumer callback) { mProducer = producer; mCallback = callback; } @@ -37,6 +38,20 @@ public class AcceptOnceConsumer implements Consumer { @Override public void accept(@NonNull T t) { mCallback.accept(t); - mProducer.removeDataChangedCallback(this); + mProducer.onConsumerReadyToBeRemoved(this); + } + + /** + * Interface to allow the {@link AcceptOnceConsumer} to notify the client that created it, + * when it is ready to be removed. This allows the client to remove the consumer object + * when it deems it is safe to do so. + * @param The type of data this callback accepts through {@link #onConsumerReadyToBeRemoved} + */ + public interface AcceptOnceProducerCallback { + + /** + * Notifies that the given {@code callback} is ready to be removed + */ + void onConsumerReadyToBeRemoved(Consumer callback); } } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/util/BaseDataProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/util/BaseDataProducer.java index cbaa277120154..46c925aaf8a27 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/util/BaseDataProducer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/util/BaseDataProducer.java @@ -19,6 +19,7 @@ package androidx.window.util; import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Optional; import java.util.Set; @@ -31,11 +32,14 @@ import java.util.function.Consumer; * * @param The type of data this producer returns through {@link DataProducer#getData}. */ -public abstract class BaseDataProducer implements DataProducer { +public abstract class BaseDataProducer implements DataProducer, + AcceptOnceConsumer.AcceptOnceProducerCallback { private final Object mLock = new Object(); @GuardedBy("mLock") private final Set> mCallbacks = new LinkedHashSet<>(); + @GuardedBy("mLock") + private final Set> mCallbacksToRemove = new HashSet<>(); /** * Adds a callback to the set of callbacks listening for data. Data is delivered through @@ -85,6 +89,26 @@ public abstract class BaseDataProducer implements DataProducer { for (Consumer callback : mCallbacks) { callback.accept(value); } + removeFinishedCallbacksLocked(); + } + } + + /** + * Removes any callbacks that notified us through {@link #onConsumerReadyToBeRemoved(Consumer)} + * that they are ready to be removed. + */ + @GuardedBy("mLock") + private void removeFinishedCallbacksLocked() { + for (Consumer callback: mCallbacksToRemove) { + mCallbacks.remove(callback); + } + mCallbacksToRemove.clear(); + } + + @Override + public void onConsumerReadyToBeRemoved(Consumer callback) { + synchronized (mLock) { + mCallbacksToRemove.add(callback); } } } \ No newline at end of file