Add a system to improve app foreground observation.

There was previously a crash that occurred when multiple threads tried to use ProcessLifecycleOwner, and this will hopefully resolve that.
This commit is contained in:
Greyson Parrelli
2021-02-08 15:37:45 -05:00
committed by GitHub
parent a160af2d11
commit 3bdf2e7e2c
13 changed files with 147 additions and 49 deletions

View File

@@ -0,0 +1,90 @@
package org.thoughtcrime.securesms.util;
import androidx.annotation.AnyThread;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleOwner;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* A wrapper around {@link ProcessLifecycleOwner} that allows for safely adding/removing observers
* on multiple threads.
*/
public final class AppForegroundObserver {
private final Set<Listener> listeners = new CopyOnWriteArraySet<>();
private volatile Boolean isForegrounded = null;
@MainThread
public void begin() {
Util.assertMainThread();
ProcessLifecycleOwner.get().getLifecycle().addObserver(new DefaultLifecycleObserver() {
@Override
public void onStart(@NonNull LifecycleOwner owner) {
onForeground();
}
@Override
public void onStop(@NonNull LifecycleOwner owner) {
onBackground();
}
});
}
/**
* Adds a listener to be notified of when the app moves between the background and the foreground.
* To mimic the behavior of subscribing to {@link ProcessLifecycleOwner}, this listener will be
* immediately notified of the foreground state if we've experienced a foreground/background event
* already.
*/
@AnyThread
public void addListener(@NonNull Listener listener) {
listeners.add(listener);
if (isForegrounded != null) {
if (isForegrounded) {
listener.onForeground();
} else {
listener.onBackground();
}
}
}
@AnyThread
public void removeListener(@NonNull Listener listener) {
listeners.remove(listener);
}
public boolean isForegrounded() {
return isForegrounded;
}
@MainThread
private void onForeground() {
isForegrounded = true;
for (Listener listener : listeners) {
listener.onForeground();
}
}
@MainThread
private void onBackground() {
isForegrounded = false;
for (Listener listener : listeners) {
listener.onBackground();
}
}
public interface Listener {
void onForeground();
void onBackground();
}
}