I have just migrated to the Fresco
library for loading images in my app.
I need to listen to Image Loading Events, of course I read this article in documentation Listening to download events
This is exactly what I need, but.... There few things that I don't like.
My goal is to hide View
if it fails to download it from the net.
I cannot reference SimpleDraweeView
from controller, even on callback method. I need to hide View
, but it seems that I cannot get reference to it.
Each time I need to load image, I need to create object of controller using Builder
, and this can cause performance issues when using this approach with list of a lot of items with images.
holder.simpleDraweeViewImage.setController(Fresco.newDraweeControllerBuilder()
.setControllerListener(controllerListener)
.setUri(currentItem.getImage())
.build());
I need to able to have reference to the SimpleDraweeView
from controller, and in MVC
pattern approach it seems okay if controller is aware about view.
Please suggest the best way to rich my goal.
Thanks.
Can hide on onFailure method:
ControllerListener listener = new BaseControllerListener<ImageInfo>() {
@Override
public void onFinalImageSet(String id, @Nullable ImageInfo imageInfo, @Nullable Animatable animatable) {
//Action on final image load
}
@Override
public void onFailure(String id, Throwable throwable) {
//Action on failure
}
};
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setUri(uri)
.setControllerListener(listener)
.build();
draweeView.setController(controller);
Regarding 1, perhaps you can do something like this:
class ControllerListenerWithView() extends BaseControllerListener {
private final WeakReference<View> mViewReference;
ControllerListenerWithView(View view) {
mViewReference = new WeakReference<>(view);
}
@Nullable
protected View getView() {
return mViewReference.get();
}
}
Then:
ControllerListener controllerListener = new ControllerListenerWithView(holder.simpleDraweeViewImage) {
@Override
public void onFailure(String id, Throwable throwable) {
View view = getView();
if (view != null) {
view.setVisibility(View.GONE);
}
}
};
If you don't have the view accessible at the listener creation time, instead of passing view via listener constructor, you can add a setter method and do:
controllerListener.setView(holder.simpleDraweeViewImage);
controller = ...
holder.simpleDraweeViewImage.setController(controller);
If this looks ugly to you, well, that's because it is ugly :) Design that involves circular references is just ugly. DraweeController doesn't have a reference to the view (not directly at least). DraweeController references a DraweeHierarchy which references Drawables and the top-level drawable has a WeakReference to the parent view in order to propagate Drawable.Callback events. But that's it. DraweeController doesn't need view and we can't/won't keep reference to the view in it. The reason for that is that DraweeControllers and DraweeHierarchies can be used in contexts other than View and it is unnecessary for controller to have a back reference to the view. DraweeController controls DraweeHierarchy, not the view.
Regarding 2, while building controller, you can specify setOldController(view.getController())
. That way the old controller which you are replacing will be reused while building a new one. This saves allocations and helps scroll-perf.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With