Fresco源码分析
Fresco的MVC模型:
M -> DraweeHierarchy 保存和管理图像层次;
V -> DraweeView 显示DraweeHierarchy的顶层图像;
C -> DraweeController 管理其他组件,设置视图层次;
DraweeHolder:controller和hierarchy的持有类,DraweeView 通过此类和controller和hierarchy交互,起到解耦作用。
DraweeHierarchy :Fresco提供了诸如占位图(加载中,加载失败显示的图片),进度条,渐进式JPEG图,多图请求及图片复用等效果,也就是说根据图片加载过程中的不同状态要显示不同效果的图片,所以需要图像的分层管理。1
2
3public interface DraweeHierarchy {
Drawable getTopLevelDrawable();
}
DraweeHierarchy代表了一个Drawee的层次,它内部维持了一个树状数据结构,DraweeHierarchy对外屏蔽了一切具体细节,只提供the top level drawable用于DraweeView的动态显示。
SettableDraweeHierarchy:继承自DraweeHierarchy并提供了一些基本的功能。1
2
3
4
5
6
7
8
9
10
11
12
13
14public interface SettableDraweeHierarchy extends DraweeHierarchy {
//将图层重置到初始状态
void reset();
//设置目标显示图片
void setImage(Drawable drawable, float progress, boolean immediate);
//设置进度条的进度
void setProgress(float progress, boolean immediate);
//设置加载失败时的图片
void setFailure(Throwable throwable);
//设置加载失败,但用户点击该图片可以重新加载
void setRetry(Throwable throwable);
//设置改图片覆盖已有的图层
void setControllerOverlay(Drawable drawable);
}
以上方法只能由controllers调用!
GenericDraweeHierarchy :实现了SettableDraweeHierarchy的基本方法,是负责装载每个图层信息的载体。1
public class GenericDraweeHierarchy implements SettableDraweeHierarchy {}
主要有顶级图层,占位符图层,目标显示图层,重新加载图层,显示失败图层, 进度条图层,控制覆盖图层。这些图层的代码位于drawable文件夹。
GenericDraweeHierarchy 的构建是通过GenericDraweeHierarchyBuilder完成的,这是典型的builder设计模式。
在GenericDraweeHierarchyBuilder可以通过一系列set方法设置诸如setPlaceholderImage,setFailureImage,setRetryImage,setProgressBarImage,setBackground(setBackgrounds),setOverlay(setOverlays),setPressedStateOverlay设置以上图层。
GenericDraweeHierarchy在初始化的时候会从GenericDraweeHierarchyBuilder提取出这些设置值。
1 | int numLayers = 0;//图层数 |
经过如下分支:
1 | //backgrounds |
将对应的图层依次序存储在数组layers中:1
2
3
4
5
6
7
8
9
10
11
12
13Drawable[] layers = new Drawable[numLayers];
if (numBackgrounds > 0) {
int index = 0;
for (Drawable background : builder.getBackgrounds()) {
layers[backgroundsIndex + index++] =
maybeApplyRoundingBitmapOnly(mRoundingParams, mResources, background);
}
}
layers[mPlaceholderImageIndex] = placeholderImageBranch;
layers[mActualImageIndex] = actualImageBranch;
layers[mProgressBarImageIndex] = progressBarImageBranch;
layers[mRetryImageIndex] = retryImageBranch;
layers[mFailureImageIndex] = failureImageBranch;
1 | //包装成FadeDrawable |
FadeDrawable继承自ArrayDrawable,ArrayDrawable包含了一个Drawables(layers)的数组,会按照数组的顺序进行绘制,角标最大的元素会被绘制在最上层。
1 | @Override |
ArrayDrawable还实现了TransformCallback, TransformAwareDrawable 接口,用以获取父图层的变换矩阵。
FadeDrawable还提供了显示/隐藏图层和渐变显示功能:
setTransitionDuration(int durationMs) 设置隐藏/显示图层渐变动画时间。
updateAlphas根据经过和持续时间计算当前的透明度。
fadeInLayer(int index) 显示指定图层。
fadeOutLayer(int index) 隐藏指定图层。
fadeInAllLayers() 显示所有图层。
fadeOutAllLayers() 隐藏所有图层。
fadeToLayer(int index) 显示指定图层同时隐藏其他图层。
fadeUpToLayer(int index) 隐藏数组下标<=index的图层。
RootDrawable继承自ForwardingDrawable,并实现了VisibilityAwareDrawable接口,用以在自身可见度改变的时候的通知函数(onVisibilityChange(boolean visible))和在自身绘制时通知回调(onDraw())。
ForwardingDrawable提供getCurrent()回去当前的容器:1
2
3public Drawable getCurrent() {
return mCurrentDelegate;
}
其设计哲学是 ,有助于重用,就像安卓原生的DrawableContainer, LevelListDrawable类那样。
DraweeView用于显示DraweeHierarchy。需要先设置hierarchy和controller。
void init(Context context) 初始化DraweeHolder;
void setHierarchy(DH hierarchy) 设置图层树并显示top level drawable
void setController(@Nullable DraweeController draweeController) 设置DraweeController并显示top level drawable
Drawable getTopLevelDrawable() 获取top level drawable;
View中的onAttachedToWindow()、 onDetachedFromWindow()、 onStartTemporaryDetach()、 onFinishTemporaryDetach() 四个回调函数,提供当视图被绑定/解绑到指定布局上时的回调函数,它们会触发DraweeHolder的onDetach()或onAttach();
设置目标图片是Controller的行为,DraweeView并不支持ImageView的setImageXxx, setScaleType和类似的方法。只有把DraweeView当作是原生的ImageView时才能调用DraweeView的如下方法:
setImageDrawable(Drawable drawable)
setImageBitmap(Bitmap bm)
setImageResource(int resId)
setImageURI(Uri uri)
这是并没有使用到Fresco的缓存和加载机制。
DraweeHolder是包含了controller和hierarchy的持有类。DraweeView的所有方法和操作都是调用了DraweeHolder的相关方法实现的。
void setHierarchy(DH hierarchy)在构造方法和DraweeView.setHierarchy中被调用,将DraweeHierarchy传给持有的DraweeControlle。
setController(@Nullable DraweeController draweeController)无条件解绑旧的Controller,并将旧DraweeController的DraweeHierarchy设置为null,并调用DraweeController.onDetach()将它变为解除绑定状态;将持有的DraweeHierarchy赋给新传入的DraweeController并调用DraweeController.onAttach()让它变为绑定状态。
1 | public void setController(@Nullable DraweeController draweeController) { |
mController.setHierarchy(mHierarchy);之后发生了什么会在后文中记述。
1 | GenericDraweeView extends DraweeView<GenericDraweeHierarchy> |
GenericDraweeView就是使用GenericDraweeHierarchy图层树的视图,GenericDraweeHierarchy图层的属性是从XML文件中获取到的。
这些属性如下:
- Fading animation parameters:
- @attr ref com.facebook.R.styleable#GenericDraweeView_fadeDuration
- Images & scale types parameters:
- @attr ref com.facebook.R.styleable#GenericDraweeView_viewAspectRatio
- @attr ref com.facebook.R.styleable#GenericDraweeView_placeholderImage
- @attr ref com.facebook.R.styleable#GenericDraweeView_placeholderImageScaleType
- @attr ref com.facebook.R.styleable#GenericDraweeView_retryImage
- @attr ref com.facebook.R.styleable#GenericDraweeView_retryImageScaleType
- @attr ref com.facebook.R.styleable#GenericDraweeView_failureImage
- @attr ref com.facebook.R.styleable#GenericDraweeView_failureImageScaleType
- @attr ref com.facebook.R.styleable#GenericDraweeView_progressBarImage
- @attr ref com.facebook.R.styleable#GenericDraweeView_progressBarImageScaleType
- @attr ref com.facebook.R.styleable#GenericDraweeView_progressBarAutoRotateInterval
- @attr ref com.facebook.R.styleable#GenericDraweeView_actualImageScaleType
- @attr ref com.facebook.R.styleable#GenericDraweeView_backgroundImage
- @attr ref com.facebook.R.styleable#GenericDraweeView_overlayImage
- @attr ref com.facebook.R.styleable#GenericDraweeView_pressedStateOverlayImage
- Rounding parameters:
- @attr ref com.facebook.R.styleable#GenericDraweeView_roundAsCircle
- @attr ref com.facebook.R.styleable#GenericDraweeView_roundedCornerRadius
- @attr ref com.facebook.R.styleable#GenericDraweeView_roundTopLeft
- @attr ref com.facebook.R.styleable#GenericDraweeView_roundTopRight
- @attr ref com.facebook.R.styleable#GenericDraweeView_roundBottomRight
- @attr ref com.facebook.R.styleable#GenericDraweeView_roundBottomLeft
- @attr ref com.facebook.R.styleable#GenericDraweeView_roundWithOverlayColor
- @attr ref com.facebook.R.styleable#GenericDraweeView_roundingBorderWidth
- @attr ref com.facebook.R.styleable#GenericDraweeView_roundingBorderColor
aspectRatio 图片的长宽比;
在inflateHierarchy方法中从XML文件中读出相关属性,并将这些属性通过GenericDraweeHierarchyBuilder完成构造,最后通过setHierarchy(builder.build())传递给GenericDraweeView。
而 SimpleDraweeView继承自GenericDraweeView,内部提供了DraweeController的简单实现。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public interface Supplier<T> {
T get();
}
private static Supplier<? extends SimpleDraweeControllerBuilder> sDraweeControllerBuilderSupplier;
public static void initialize(
Supplier<? extends SimpleDraweeControllerBuilder> draweeControllerBuilderSupplier) {
sDraweeControllerBuilderSupplier = draweeControllerBuilderSupplier;
}
private void init() {
if (isInEditMode()) {
return;
}
Preconditions.checkNotNull(
sDraweeControllerBuilderSupplier,
"SimpleDraweeView was not initialized!");
mSimpleDraweeControllerBuilder = sDraweeControllerBuilderSupplier.get();
}
setImageURI方法:1
2
3
4
5
6
7
8public void setImageURI(Uri uri, @Nullable Object callerContext) {
DraweeController controller = mSimpleDraweeControllerBuilder
.setCallerContext(callerContext)
.setUri(uri)
.setOldController(getController())
.build();
setController(controller);
}
下面到了controller的部分:
The view forwards events to the controller. The controller controls its hierarchy based on those events.1
2
3
4
5
6
7
8
9public interface DraweeController {
DraweeHierarchy getHierarchy();
void setHierarchy(@Nullable DraweeHierarchy hierarchy);
void onAttach();
void onDetach();
boolean onTouchEvent(MotionEvent event);
Animatable getAnimatable();
}
1 | abstract class AbstractDraweeController<T, INFO> implements |
DraweeView在onAttachedToWindow()方法中调用mDraweeHolder.onAttach();该方法内部调用 mController.onAttach();
1 | if (mController != null && |
会先判断是否已经给mController设置了hierarchy。
下面我们看AbstractDraweeController的onAttach()方法内部的submitRequest()方法。
1 | protected void submitRequest() { |
发现这是观察者设计模式,DataScriber订阅了DataSource的信息,在不同的回调函数中onNewResultImpl,onFailureImpl,onProgressUpdate对DraweeHierarchy做出相应的处理。
下面是图片加载失败情况下的主要代码:
1 | if (isFinished) { |
AbstractDraweeController是通过AbstractDraweeControllerBuilder的build()方法构建的。
其重要方法还有Supplier
获取被controller使用的the top-level数据源的supplier 。