fix SingleLiveData memory leak

androidx
Zhanty 5 years ago
parent 5da1dfbd64
commit bc7ca1b9a5
  1. 80
      lib_social/src/main/java/com/android/sdk/social/wechat/SingleLiveData.java

@ -4,14 +4,21 @@ 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.WeakHashMap; import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
class SingleLiveData<T> extends MediatorLiveData<T> { import timber.log.Timber;
public class SingleLiveData<T> extends MediatorLiveData<T> {
private int mVersion = 0; private int mVersion = 0;
private final WeakHashMap<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) {
@ -23,20 +30,6 @@ class SingleLiveData<T> extends MediatorLiveData<T> {
super.observeForever(getOrNewObserver(observer, mVersion)); super.observeForever(getOrNewObserver(observer, mVersion));
} }
private Observer<T> getOrNewObserver(@NonNull Observer<T> observer, int observerVersion) {
Observer<T> wrapper = cache.get(observer);
if (wrapper == null) {
wrapper = t -> {
if (observerVersion < mVersion) {
observer.onChanged(t);
}
};
cache.put(observer, wrapper);
}
return wrapper;
}
@Override @Override
public void setValue(T value) { public void setValue(T value) {
mVersion++; mVersion++;
@ -45,10 +38,61 @@ 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 + "]");
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) {
ObserverWrapper<T> wrapper = findWrapper(observer);
if (wrapper == null) {
wrapper = new ObserverWrapper<>(observerVersion, observer);
mWrapperObserverList.add(new WeakReference<>(wrapper));
}
Timber.d("getOrNewObserver() called with: observer = [" + observer + "], observerVersion = [" + observerVersion + "], wrapper = [" + 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