fix SingleLiveData memory leak

androidx
Zhanty 5 years ago
parent 647f35132a
commit 5da1dfbd64
  1. 60
      lib_base/src/main/java/com/android/base/app/aac/SingleLiveData.java

@ -4,9 +4,12 @@ import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.MediatorLiveData; import android.arch.lifecycle.MediatorLiveData;
import android.arch.lifecycle.Observer; import android.arch.lifecycle.Observer;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.Map; import java.lang.ref.WeakReference;
import java.util.WeakHashMap; import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import timber.log.Timber; import timber.log.Timber;
@ -14,7 +17,8 @@ public class SingleLiveData<T> extends MediatorLiveData<T> {
private int mVersion = 0; private int mVersion = 0;
private final Map<Observer<T>, Observer<T>> cache = new WeakHashMap<>(); private final List<WeakReference<ObserverWrapper<T>>> mWrapperObserverList = new ArrayList<>();
@Override @Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) { public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
@ -34,23 +38,37 @@ public class SingleLiveData<T> extends MediatorLiveData<T> {
@Override @Override
public void removeObserver(@NonNull Observer<T> observer) { public void removeObserver(@NonNull Observer<T> observer) {
Observer<T> wrapper = cache.remove(observer); Observer<T> wrapper = findWrapper(observer);
Timber.d("removeObserver() called with: observer = [" + observer + "], wrapper = [" + wrapper + "]"); Timber.d("removeObserver() called with: observer = [" + observer + "], wrapper = [" + wrapper + "]");
if (wrapper != null) { if (wrapper != null) {
super.removeObserver(wrapper); super.removeObserver(wrapper);
} }
} }
private ObserverWrapper<T> findWrapper(Observer<T> observer) {
ListIterator<WeakReference<ObserverWrapper<T>>> iterator = mWrapperObserverList.listIterator();
ObserverWrapper<T> target = null;
while (iterator.hasNext()) {
WeakReference<ObserverWrapper<T>> next = iterator.next();
ObserverWrapper<T> item = next.get();
if (item == null) {
iterator.remove();
} else if (item.mOrigin == observer) {
target = item;
}
}
return target;
}
private Observer<T> getOrNewObserver(@NonNull Observer<T> observer, int observerVersion) { private Observer<T> getOrNewObserver(@NonNull Observer<T> observer, int observerVersion) {
Observer<T> wrapper = cache.get(observer); ObserverWrapper<T> wrapper = findWrapper(observer);
if (wrapper == null) { if (wrapper == null) {
wrapper = t -> { wrapper = new ObserverWrapper<>(observerVersion, observer);
if (observerVersion < mVersion) { mWrapperObserverList.add(new WeakReference<>(wrapper));
observer.onChanged(t);
}
};
cache.put(observer, wrapper);
} }
Timber.d("getOrNewObserver() called with: observer = [" + observer + "], observerVersion = [" + observerVersion + "], wrapper = [" + wrapper + "]"); Timber.d("getOrNewObserver() called with: observer = [" + observer + "], observerVersion = [" + observerVersion + "], wrapper = [" + wrapper + "]");
@ -58,4 +76,24 @@ public class SingleLiveData<T> extends MediatorLiveData<T> {
return wrapper; return wrapper;
} }
private class ObserverWrapper<E> implements Observer<E> {
private final int mObserverVersion;
private final Observer<E> mOrigin;
private ObserverWrapper(int observerVersion, Observer<E> origin) {
mObserverVersion = observerVersion;
mOrigin = origin;
}
@Override
public void onChanged(@Nullable E t) {
if (mObserverVersion < mVersion && mOrigin != null) {
mOrigin.onChanged(t);
}
}
}
} }
Loading…
Cancel
Save