个人博客地址: 斯科特安的时间
使用 LoaderManager 管理 Loader,会默认注册一个 OnLoadCompleteListener
, 而这个 Listener 只能注册一个。重复注册会报这个错误:
Caused by: java.lang.IllegalStateException:
There is already a listener registered
at android.support.v4.content.Loader.registerListener(Loader.java:130)
源码是这样:
public void registerListener(int id, OnLoadCompleteListener<D> listener) {
if (mListener != null) {
throw new IllegalStateException("There is already a listener registered");
}
mListener = listener;
mId = id;
}
我们看到方法名叫 register...
自然想到可以使用 unregister...
方法。
然而由于这个 listener 是 LoaderManager
帮助注册的,除非使用一些非常规方法 (比如反射),我们不能也不合适去手动 unregister。
别人的解决方案
网络很多人认为这是 android 的 bug,可以通过每次重新新建 Loader 解决:
Override
public YourLoader onCreateLoader(int arg0, Bundle bundle) {
return new YourLoader(getContext()...);
}
然而这个方法并不是特别优雅
一个比较优雅的解决方案是 extends Loader, 重写一套回调方法。
查看源码我们看看原来怎么回调的:
public void deliverResult(D data) {
if (mListener != null) {
mListener.onLoadComplete(this, data);
}
}
public void deliverCancellation() {
if (mOnLoadCanceledListener != null) {
mOnLoadCanceledListener.onLoadCanceled(this);
}
}
那我们只需要重写这两个方法就可以了,新的 ObservableLoader
如下:
public abstract class ObservableLoader<D> extends AsyncTaskLoader<D> {
public ObservableLoader(Context context) {
super(context);
}
@Override
public void deliverResult(D data) {
super.deliverResult(data);
notifyLoadCompleted(this, data);
}
@Override
public void deliverCancellation() {
super.deliverCancellation();
notifyLoadCancelled(this);
}
public interface LoaderObserver<D> {
void onLoadCompleted(Loader<D> loader, D data);
void onLoadCancelled(Loader<D> loader);
}
private List<LoaderObserver<D>> mObservers = new ArrayList<>();
public void addObserver(@NonNull LoaderObserver<D> observer) {
if (!mObservers.contains(observer)) {
mObservers.add(observer);g
}
}
public void removeObserver(@NonNull LoaderObserver<D> observer) {
if (mObservers.contains(observer)) {
mObservers.remove(observer);
}
}
public void notifyLoadCompleted(Loader<D> loader, D data) {
for (LoaderObserver<D> observer : mObservers) {
observer.onLoadCompleted(loader, data);
}
}
public void notifyLoadCancelled(Loader<D> loader) {
for (LoaderObserver<D> observer : mObservers) {
observer.onLoadCancelled(loader);
}
}
}