Fresco學(xué)習(xí)中文地址:Fresco中文學(xué)習(xí)
Fresco Javadoc地址:Javadoc
Fresco初始化分析:
在Application中加入:
Fresco.initialize(this);
請(qǐng)看我的注釋:
/*
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.drawee.backends.pipeline;
import *
/**
* Fresco entry point.(總體入口點(diǎn))
*
* <p/> You must initialize this class before use. The simplest way is to just do
* {#code Fresco.initialize(Context)}.
* (指明了一個(gè)簡(jiǎn)單例子)
*/
public class Fresco {
private static PipelineDraweeControllerBuilderSupplier sDraweeControllerBuilderSupplier; //業(yè)務(wù)邏輯工廠
private Fresco() {}
/** Initializes Fresco with the default config. */
public static void initialize(Context context) {
ImagePipelineFactory.initialize(context); // 關(guān)系圖片下載邏輯處理和緩存處理
initializeDrawee(context);
}
/** Initializes Fresco with the specified config. */
public static void initialize(Context context, ImagePipelineConfig imagePipelineConfig) {
ImagePipelineFactory.initialize(imagePipelineConfig); // 關(guān)系圖片下載邏輯處理和緩存處理
initializeDrawee(context);
}
private static void initializeDrawee(Context context) {
sDraweeControllerBuilderSupplier = new PipelineDraweeControllerBuilderSupplier(context);
SimpleDraweeView.initialize(sDraweeControllerBuilderSupplier); // 這個(gè)SimpleDraweeView是在布局中使用的代理Imageview辛孵,掛在一堆轉(zhuǎn)換邏輯
}
/** Gets the supplier of Fresco Drawee controller builders. */
public static PipelineDraweeControllerBuilderSupplier getDraweeControllerBuilderSupplier() {
return sDraweeControllerBuilderSupplier; // 這貨給外部使用,看需求而定
}
/** Returns a new instance of Fresco Drawee controller builder. */
public static PipelineDraweeControllerBuilder newDraweeControllerBuilder() {
return sDraweeControllerBuilderSupplier.get(); // 給外部需求所用,拿到一個(gè)新的業(yè)務(wù)邏輯工廠對(duì)象
}
public static ImagePipelineFactory getImagePipelineFactory() {
return ImagePipelineFactory.getInstance(); // 外部使用的管道類踢故,這貨檢查是否初始化
}
/** Gets the image pipeline instance. */
public static ImagePipeline getImagePipeline() {
return getImagePipelineFactory().getImagePipeline();// 外部使用的管道類,這貨檢查是否初始化嗤栓,沒(méi)有給你個(gè)新的佑刷,工廠模式
}
/** Shuts Fresco down. */
public static void shutDown() { //Application 退出調(diào)用,避免內(nèi)存泄露
sDraweeControllerBuilderSupplier = null;
SimpleDraweeView.shutDown();
ImagePipelineFactory.shutDown();
}
}
初始化翻譯就這樣:
Fresco.initialize() ===> Fresco.initializeDrawee() ===> SimpleDraweeView.initialize();
請(qǐng)繼續(xù)看我的注釋:
/*
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.drawee.view;
import *
/**
* This view takes a uri as input and internally builds and sets a controller.(這個(gè)類就是掛載url和control準(zhǔn)備)
*
* <p>This class must be statically initialized in order to be used. If you are using the Fresco
* image pipeline, use {@link com.facebook.drawee.backends.pipeline.Fresco#initialize} to do this.
* (官方教育你钝计,先初始化Fresco.initialize)
*/
public class SimpleDraweeView extends GenericDraweeView { // 這個(gè)繼承有點(diǎn)深恋博,慢慢來(lái),最終爸爸肯定是ImageView私恬,但每個(gè)繼承做了深度定制
private static Supplier<? extends SimpleDraweeControllerBuilder> sDraweeControllerBuilderSupplier;// 這貨就是前面初始化進(jìn)來(lái)的業(yè)務(wù)邏輯提供者
/** Initializes {@link SimpleDraweeView} with supplier of Drawee controller builders. */
public static void initialize( // 初始化傳值
Supplier<? extends SimpleDraweeControllerBuilder> draweeControllerBuilderSupplier) {
sDraweeControllerBuilderSupplier = draweeControllerBuilderSupplier;
}
/** Shuts {@link SimpleDraweeView} down. */
public static void shutDown() { // 關(guān)閉
sDraweeControllerBuilderSupplier = null;
}
private SimpleDraweeControllerBuilder mSimpleDraweeControllerBuilder; // 真正的業(yè)務(wù)邏輯對(duì)象债沮,從sDraweeControllerBuilderSupplier拿出
public SimpleDraweeView(Context context, GenericDraweeHierarchy hierarchy) {
super(context, hierarchy);
init(context, null);
}
public SimpleDraweeView(Context context) {
super(context);
init(context, null);
}
public SimpleDraweeView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public SimpleDraweeView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SimpleDraweeView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, @Nullable AttributeSet attrs) {
if (isInEditMode()) { // 來(lái)自view,是否控件可以編輯
return;
}
Preconditions.checkNotNull(
sDraweeControllerBuilderSupplier,
"SimpleDraweeView was not initialized!"); // 檢查sDraweeControllerBuilderSupplier
mSimpleDraweeControllerBuilder = sDraweeControllerBuilderSupplier.get(); // 拿到對(duì)應(yīng)的業(yè)務(wù)邏輯(正常來(lái)說(shuō)都是PipelineDraweeControllerBuilder本鸣,如果自己沒(méi)有外部定制需求)
// 拿布局屬性疫衩,基本無(wú)用,可以是個(gè)默認(rèn)圖uri
if (attrs != null) {
TypedArray gdhAttrs = context.obtainStyledAttributes(
attrs,
R.styleable.SimpleDraweeView);
try {
if (gdhAttrs.hasValue(R.styleable.SimpleDraweeView_actualImageUri)) {
setImageURI(Uri.parse(gdhAttrs.getString(R.styleable.SimpleDraweeView_actualImageUri)), null);
}
} finally {
gdhAttrs.recycle();
}
}
}
protected SimpleDraweeControllerBuilder getControllerBuilder() { // 給外部使用荣德,沒(méi)有什么好說(shuō)的
return mSimpleDraweeControllerBuilder;
}
/**
* Displays an image given by the uri.
*
* @param uri uri of the image
* @undeprecate
*/
@Override
public void setImageURI(Uri uri) { // 定制網(wǎng)絡(luò)圖片url
setImageURI(uri, null);
}
/**
* Displays an image given by the uri string.
*
* @param uriString uri string of the image
*/
public void setImageURI(@Nullable String uriString) {
setImageURI(uriString, null);
}
/**
* Displays an image given by the uri.
*
* @param uri uri of the image
* @param callerContext caller context
*/
public void setImageURI(Uri uri, @Nullable Object callerContext) { // builder模式建立DraweeController
DraweeController controller = mSimpleDraweeControllerBuilder
.setCallerContext(callerContext)// 這貨如果沒(méi)有指定闷煤,都是null,一直傳到所有的生產(chǎn)者中
.setUri(uri)
.setOldController(getController())// 這貨首次是null
.build();
setController(controller);
}
/**
* Displays an image given by the uri string.
*
* @param uriString uri string of the image
* @param callerContext caller context
*/
public void setImageURI(@Nullable String uriString, @Nullable Object callerContext) { // 多態(tài)
Uri uri = (uriString != null) ? Uri.parse(uriString) : null;
setImageURI(uri, callerContext);
}
}
SimpleDraweeView 的繼承先不看命爬,控件處理而已曹傀,先看完關(guān)心request流程。
流程:SimpleDraweeView.setImageURI() ===> PipelineDraweeControllerBuilder.build(),然后SimpleDraweeView 再持有PipelineDraweeController這個(gè)對(duì)象
接著看注釋饲宛,這個(gè)build類:
package com.facebook.drawee.backends.pipeline;
import *
/**
* Concrete implementation of ImagePipeline Drawee controller builder. (業(yè)務(wù)邏輯實(shí)現(xiàn)類)
* <p/> See {@link AbstractDraweeControllerBuilder} for more details.
*/
public class PipelineDraweeControllerBuilder extends AbstractDraweeControllerBuilder<
PipelineDraweeControllerBuilder,
ImageRequest,
CloseableReference<CloseableImage>,
ImageInfo> { // 很多實(shí)現(xiàn)在基類AbstractDraweeControllerBuilder完成皆愉,如果你需要定制自己DraweeController,繼承這個(gè)基類
private final ImagePipeline mImagePipeline; // 各種緩存和策略艇抠,維護(hù)臟活的就是它
private final PipelineDraweeControllerFactory mPipelineDraweeControllerFactory;// 這貨持有uiThread幕庐,用來(lái)回掉更新,配合ImagePipeline 完成請(qǐng)求
public PipelineDraweeControllerBuilder(
Context context,
PipelineDraweeControllerFactory pipelineDraweeControllerFactory,
ImagePipeline imagePipeline,
Set<ControllerListener> boundControllerListeners) {
super(context, boundControllerListeners);
mImagePipeline = imagePipeline;
mPipelineDraweeControllerFactory = pipelineDraweeControllerFactory;
}
@Override
public PipelineDraweeControllerBuilder setUri(Uri uri) { // 轉(zhuǎn)換成一個(gè)ImageRequest
return super.setImageRequest(ImageRequest.fromUri(uri));
}
@Override
public PipelineDraweeControllerBuilder setUri(@Nullable String uriString) { // 轉(zhuǎn)換成一個(gè)ImageRequest
return super.setImageRequest(ImageRequest.fromUri(uriString));
}
// 這個(gè)函數(shù)來(lái)自SimpleDraweeView:setImageURI():PipelineDraweeControllerBuilder.build()
@Override
protected PipelineDraweeController obtainController() { // 父類會(huì)回掉家淤,首次會(huì)走else异剥,為了重復(fù)使用,把新數(shù)據(jù)更新到controller中
DraweeController oldController = getOldController();
PipelineDraweeController controller;
if (oldController instanceof PipelineDraweeController) {
controller = (PipelineDraweeController) oldController;
controller.initialize(
obtainDataSourceSupplier(),
generateUniqueControllerId(),
getCacheKey(),
getCallerContext());
} else {
controller = mPipelineDraweeControllerFactory.newController(
obtainDataSourceSupplier(),
generateUniqueControllerId(),
getCacheKey(),
getCallerContext());
}
return controller;
}
private CacheKey getCacheKey() { // 根據(jù)imageRequest 拿到對(duì)應(yīng)的Cache策略絮重,這貨從ImagePipeline 拿到Cache
final ImageRequest imageRequest = getImageRequest();
final CacheKeyFactory cacheKeyFactory = mImagePipeline.getCacheKeyFactory();
CacheKey cacheKey = null;
if (cacheKeyFactory != null && imageRequest != null) {
if (imageRequest.getPostprocessor() != null) {
cacheKey = cacheKeyFactory.getPostprocessedBitmapCacheKey(
imageRequest,
getCallerContext());
} else {
cacheKey = cacheKeyFactory.getBitmapCacheKey(
imageRequest,
getCallerContext());
}
}
return cacheKey;
}
// 數(shù)據(jù)Bean冤寿,帶有回掉數(shù)據(jù)接口(成功或者失敗),利用執(zhí)行ImagePipeline request
@Override
protected DataSource<CloseableReference<CloseableImage>> getDataSourceForRequest(
ImageRequest imageRequest,
Object callerContext,
boolean bitmapCacheOnly) {
if (bitmapCacheOnly) {
return mImagePipeline.fetchImageFromBitmapCache(imageRequest, callerContext);
} else {
return mImagePipeline.fetchDecodedImage(imageRequest, callerContext);
}
}
.......
}
好了大致知道了Cache類和Executor類了青伤,都來(lái)自ImagePipeline督怜。
ImagePipeline 負(fù)責(zé)圖片的獲取和管理。圖片可以來(lái)自遠(yuǎn)程服務(wù)器狠角,本地文件号杠,或者Content Provider,本地資源。壓縮后的文件緩存在本地存儲(chǔ)中姨蟋,Bitmap數(shù)據(jù)緩存在內(nèi)存中屉凯。
obtainController(),這個(gè)函數(shù)比較重要,構(gòu)造了業(yè)務(wù)邏輯眼溶,有點(diǎn)像MVC悠砚,這里創(chuàng)建后生成回掉,給后面view偷仿,addWindow()后哩簿,收集WMS和IMS(WindowManagerService和InputeManagerService)產(chǎn)生的生命周期回掉或者輸入事件綁定。
在5.0系統(tǒng)以下酝静,Image Pipeline 使用 pinned purgeables 將Bitmap數(shù)據(jù)避開(kāi)Java堆內(nèi)存节榜,存在ashmem中。這要求圖片不使用時(shí)别智,要顯式地釋放內(nèi)存宗苍。
SimpleDraweeView自動(dòng)處理了這個(gè)釋放過(guò)程,所以沒(méi)有特殊情況薄榛,盡量使用SimpleDraweeView讳窟,在特殊的場(chǎng)合,如果有需要敞恋,也可以直接控制Image Pipeline丽啡。
ImagePipeline介紹來(lái)自
關(guān)于ImagePipeline后面文章介紹里面策略和緩存詳細(xì),先看主request
那執(zhí)行Requst代碼在哪硬猫,在前面SimpleDraweeView.setImageURI()里面是執(zhí)行
package com.facebook.drawee.backends.pipeline;
import *
/**
* Drawee controller that bridges the image pipeline with {@link SettableDraweeHierarchy}. <p> The
* hierarchy's actual image is set to the image(s) obtained by the provided data source. The data
* source is automatically obtained and closed based on attach / detach calls.
*/
public class PipelineDraweeController
extends AbstractDraweeController<CloseableReference<CloseableImage>, ImageInfo> {
// Components
private final Resources mResources;
private final AnimatedDrawableFactory mAnimatedDrawableFactory;
private @Nullable MemoryCache<CacheKey, CloseableImage> mMemoryCache;
private static Experiment sExperiment; // 這貨相當(dāng)于一個(gè)對(duì)象鎖
private CacheKey mCacheKey;
// Constant state (non-final because controllers can be reused)
private Supplier<DataSource<CloseableReference<CloseableImage>>> mDataSourceSupplier;
public PipelineDraweeController( // 初始化和傳值一堆补箍,為了基類使用
Resources resources,
DeferredReleaser deferredReleaser,
AnimatedDrawableFactory animatedDrawableFactory,
Executor uiThreadExecutor,
MemoryCache<CacheKey, CloseableImage> memoryCache,
Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier,
String id,
CacheKey cacheKey,
Object callerContext) {
super(deferredReleaser, uiThreadExecutor, id, callerContext);
mResources = resources;
mAnimatedDrawableFactory = animatedDrawableFactory;
mMemoryCache = memoryCache;
mCacheKey = cacheKey;
init(dataSourceSupplier);
}
public void initialize(
Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier,
String id,
CacheKey cacheKey,
Object callerContext) {
super.initialize(id, callerContext);
init(dataSourceSupplier);
mCacheKey = cacheKey;
}
private void init(Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier) {
mDataSourceSupplier = dataSourceSupplier;
}
// 這個(gè)函數(shù)比較重要,利用DataSourceSupplier提供model接口數(shù)據(jù)接口(MVC模式)
@Override
protected DataSource<CloseableReference<CloseableImage>> getDataSource() { // 更新數(shù)據(jù)的接口,有成功和失敗
if (FLog.isLoggable(FLog.VERBOSE)) {
FLog.v(TAG, "controller %x: getDataSource", System.identityHashCode(this));
}
return mDataSourceSupplier.get();
}
@Override
protected Drawable createDrawable(CloseableReference<CloseableImage> image) {// 創(chuàng)建Drawable的策略回掉
Preconditions.checkState(CloseableReference.isValid(image));
CloseableImage closeableImage = image.get();
if (closeableImage instanceof CloseableStaticBitmap) {
CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) closeableImage;
Drawable bitmapDrawable = new BitmapDrawable(
mResources,
closeableStaticBitmap.getUnderlyingBitmap());
if (closeableStaticBitmap.getRotationAngle() == 0 ||
closeableStaticBitmap.getRotationAngle() == EncodedImage.UNKNOWN_ROTATION_ANGLE) {
return bitmapDrawable;
} else {
return new OrientedDrawable(bitmapDrawable, closeableStaticBitmap.getRotationAngle());
}
} else if (mAnimatedDrawableFactory != null) {
return mAnimatedDrawableFactory.create(closeableImage);
} else {
throw new UnsupportedOperationException("Unrecognized image class: " + closeableImage);
}
}
.......
@Override
protected void releaseImage(@Nullable CloseableReference<CloseableImage> image) { // 釋放引用策略
CloseableReference.closeSafely(image);
}
@Override
protected void releaseDrawable(@Nullable Drawable drawable) { // 釋放引用策略
if (drawable instanceof DrawableWithCaches) {
((DrawableWithCaches) drawable).dropCaches();
}
}
@Override
protected CloseableReference<CloseableImage> getCachedImage() { // 關(guān)閉引用策略
if (!getExperiment().mIsFastCheckEnabled) {
return null;
}
if (mMemoryCache == null || mCacheKey == null) {
return null;
}
// We get the CacheKey
CloseableReference<CloseableImage> closeableImage = mMemoryCache.get(mCacheKey);
if (closeableImage != null && !closeableImage.get().getQualityInfo().isOfFullQuality()) {
closeableImage.close();
return null;
}
return closeableImage;
}
/**
* @return The Experiment object
*/
protected static Experiment getExperiment() {
if (sExperiment == null) {
sExperiment = new Experiment();
}
return sExperiment;
}
protected static class Experiment { // 檢查類
private boolean mIsFastCheckEnabled;
public Experiment setFastCheckEnabled(final boolean fastCheckEnabled) {
mIsFastCheckEnabled = fastCheckEnabled;
return this;
}
}
}
上面只是實(shí)力類,真正調(diào)用在基類, 比較重要的就是getDataSource()和createDrawable()的實(shí)現(xiàn)了读规,其它都是釋放資源和回收,后面再講這個(gè)資源回收和回掉過(guò)程
接下來(lái)看基類指明干活
package com.facebook.drawee.controller;
import *
/**
* Abstract Drawee controller that implements common functionality
* regardless of the backend used to fetch the image.
*
* All methods should be called on the main UI thread.
*
*/
@NotThreadSafe
public abstract class AbstractDraweeController<T, INFO> implements
DraweeController,
DeferredReleaser.Releasable,
GestureDetector.ClickListener {
/**
* This class is used to allow an optimization of not creating a ForwardingControllerListener
* when there is only a single controller listener.
* 這貨也比較重要裹粤,但尼瑪你沒(méi)有定制自己controllistener,默認(rèn)為null蜂林,沒(méi)有什么卵用
*/
private static class InternalForwardingListener<INFO> extends ForwardingControllerListener<INFO> {
public static <INFO> InternalForwardingListener<INFO> createInternal(
ControllerListener<? super INFO> listener1,
ControllerListener<? super INFO> listener2) {
InternalForwardingListener<INFO> forwarder = new InternalForwardingListener<INFO>();
forwarder.addListener(listener1);
forwarder.addListener(listener2);
return forwarder;
}
}
// Components
private final DraweeEventTracker mEventTracker = DraweeEventTracker.newInstance(); // 日志追蹤
private final DeferredReleaser mDeferredReleaser; // 賴加載遥诉,延遲安排任務(wù)
private final Executor mUiThreadImmediateExecutor; // ui線程從PipelineDraweeControllerBuilder :PipelineDraweeControllerFactory 來(lái)的
// Optional components
private @Nullable RetryManager mRetryManager; // 重試機(jī)制
private @Nullable GestureDetector mGestureDetector; // 手勢(shì)
private @Nullable ControllerListener<INFO> mControllerListener; // 業(yè)務(wù)邏輯回掉監(jiān)聽(tīng)
// Hierarchy
private @Nullable SettableDraweeHierarchy mSettableDraweeHierarchy; // view對(duì)象樹(shù), 用于組織和維護(hù)最終繪制和呈現(xiàn)的 Drawable 對(duì)象
private @Nullable Drawable mControllerOverlay; // view對(duì)象
// Constant state (non-final because controllers can be reused)
private String mId;
private Object mCallerContext;
// Mutable state
private boolean mIsAttached; // 是否view添加到window上
private boolean mIsRequestSubmitted; // 是否已經(jīng)開(kāi)始request
private boolean mHasFetchFailed;// 當(dāng)前request更新失敗flag
private boolean mRetainImageOnFailure;// 設(shè)置是否顯示最新的可用的圖片(默認(rèn)圖)噪叙,在失敗的時(shí)候
private @Nullable String mContentDescription; // 描述
private @Nullable DataSource<T> mDataSource; // 子類data策略
private @Nullable T mFetchedImage; // 獲取到當(dāng)前image
private @Nullable Drawable mDrawable; // 圖片資源
public AbstractDraweeController(
DeferredReleaser deferredReleaser,
Executor uiThreadImmediateExecutor,
String id,
Object callerContext) {
mDeferredReleaser = deferredReleaser;
mUiThreadImmediateExecutor = uiThreadImmediateExecutor;
init(id, callerContext, true);
}
protected void initialize(String id, Object callerContext) {
init(id, callerContext, false);
}
private void init(String id, Object callerContext, boolean justConstructed) {
mEventTracker.recordEvent(Event.ON_INIT_CONTROLLER);
// cancel deferred release
if (!justConstructed && mDeferredReleaser != null) {
mDeferredReleaser.cancelDeferredRelease(this);
}
// reinitialize mutable state (fetch state)
mIsAttached = false;
releaseFetch();
mRetainImageOnFailure = false;
// reinitialize optional components
if (mRetryManager != null) {
mRetryManager.init();
}
if (mGestureDetector != null) {
mGestureDetector.init();
mGestureDetector.setClickListener(this);
}
if (mControllerListener instanceof InternalForwardingListener) {
((InternalForwardingListener) mControllerListener).clearListeners();
} else {
mControllerListener = null;
}
// clear hierarchy and controller overlay
if (mSettableDraweeHierarchy != null) {
mSettableDraweeHierarchy.reset();
mSettableDraweeHierarchy.setControllerOverlay(null);
mSettableDraweeHierarchy = null;
}
mControllerOverlay = null;
// reinitialize constant state
if (FLog.isLoggable(FLog.VERBOSE)) {
FLog.v(TAG, "controller %x %s -> %s: initialize", System.identityHashCode(this), mId, id);
}
mId = id;
mCallerContext = callerContext;
}
@Override
public void release() {
mEventTracker.recordEvent(Event.ON_RELEASE_CONTROLLER);
if (mRetryManager != null) {
mRetryManager.reset();
}
if (mGestureDetector != null) {
mGestureDetector.reset();
}
if (mSettableDraweeHierarchy != null) {
mSettableDraweeHierarchy.reset();
}
releaseFetch();
}
private void releaseFetch() { // 釋放hold的image和data突那,為request做準(zhǔn)備
boolean wasRequestSubmitted = mIsRequestSubmitted;
mIsRequestSubmitted = false;
mHasFetchFailed = false;
if (mDataSource != null) {
mDataSource.close();
mDataSource = null;
}
if (mDrawable != null) {
releaseDrawable(mDrawable);
}
if (mContentDescription != null) {
mContentDescription = null;
}
mDrawable = null;
if (mFetchedImage != null) {
logMessageAndImage("release", mFetchedImage);
releaseImage(mFetchedImage);
mFetchedImage = null;
}
if (wasRequestSubmitted) {
getControllerListener().onRelease(mId);
}
}
public Object getCallerContext() { // 默認(rèn)情況都是null,基本無(wú)卵用构眯,如果你有特殊要求,這個(gè)上下文能起到很大重要早龟,如惫霸,日志追蹤
return mCallerContext;
}
protected @Nullable RetryManager getRetryManager() { // 重試機(jī)制
return mRetryManager;
}
.......
/** Gets gesture detector. */
protected @Nullable GestureDetector getGestureDetector() {
return mGestureDetector;
}
/** Sets gesture detector. */
protected void setGestureDetector(@Nullable GestureDetector gestureDetector) {
mGestureDetector = gestureDetector;
if (mGestureDetector != null) {
mGestureDetector.setClickListener(this);
}
}
// 這貨有意思了猫缭,這貨給你個(gè)flag,需要set進(jìn)來(lái)壹店,作用是你下載完后猜丹,失敗需要重新下載標(biāo)志
protected void setRetainImageOnFailure(boolean enabled) {
mRetainImageOnFailure = enabled;
}
.......
// 基本無(wú)用,默認(rèn)是null硅卢,為了完成你自己定制的回掉監(jiān)聽(tīng)設(shè)置
/** Adds controller listener. */
public void addControllerListener(ControllerListener<? super INFO> controllerListener) {
Preconditions.checkNotNull(controllerListener);
if (mControllerListener instanceof InternalForwardingListener) {
((InternalForwardingListener<INFO>) mControllerListener).addListener(controllerListener);
return;
}
if (mControllerListener != null) {
mControllerListener = InternalForwardingListener.createInternal(
mControllerListener,
controllerListener);
return;
}
// Listener only receives <INFO>, it never produces one.
// That means if it can accept <? super INFO>, it can very well accept <INFO>.
mControllerListener = (ControllerListener<INFO>) controllerListener;
}
.......
/** Gets controller listener for internal use. */
protected ControllerListener<INFO> getControllerListener() {
if (mControllerListener == null) {
return BaseControllerListener.getNoOpListener();
}
return mControllerListener;
}
/** Gets the hierarchy */
@Override
public @Nullable
DraweeHierarchy getHierarchy() {
return mSettableDraweeHierarchy;
}
// 這函數(shù)比較屌射窒,維護(hù)view樹(shù),以后再講
@Override
public void setHierarchy(@Nullable DraweeHierarchy hierarchy) {
if (FLog.isLoggable(FLog.VERBOSE)) {
FLog.v(
TAG,
"controller %x %s: setHierarchy: %s",
System.identityHashCode(this),
mId,
hierarchy);
}
mEventTracker.recordEvent(
(hierarchy != null) ? Event.ON_SET_HIERARCHY : Event.ON_CLEAR_HIERARCHY);
// force release in case request was submitted
if (mIsRequestSubmitted) {
mDeferredReleaser.cancelDeferredRelease(this);
release();
}
// clear the existing hierarchy
if (mSettableDraweeHierarchy != null) {
mSettableDraweeHierarchy.setControllerOverlay(null);
mSettableDraweeHierarchy = null;
}
// set the new hierarchy
if (hierarchy != null) {
Preconditions.checkArgument(hierarchy instanceof SettableDraweeHierarchy);
mSettableDraweeHierarchy = (SettableDraweeHierarchy) hierarchy;
mSettableDraweeHierarchy.setControllerOverlay(mControllerOverlay);
}
}
/** Sets the controller overlay */
protected void setControllerOverlay(@Nullable Drawable controllerOverlay) {
mControllerOverlay = controllerOverlay;
if (mSettableDraweeHierarchy != null) {
mSettableDraweeHierarchy.setControllerOverlay(mControllerOverlay);
}
}
/** Gets the controller overlay */
protected @Nullable Drawable getControllerOverlay() {
return mControllerOverlay;
}
@Override
public void onAttach() { // 回調(diào)
if (FLog.isLoggable(FLog.VERBOSE)) {
FLog.v(
TAG,
"controller %x %s: onAttach: %s",
System.identityHashCode(this),
mId,
mIsRequestSubmitted ? "request already submitted" : "request needs submit");
}
mEventTracker.recordEvent(Event.ON_ATTACH_CONTROLLER);
Preconditions.checkNotNull(mSettableDraweeHierarchy);
mDeferredReleaser.cancelDeferredRelease(this);
mIsAttached = true;
if (!mIsRequestSubmitted) {
submitRequest();
}
}
@Override
public void onDetach() { // 回調(diào)
if (FLog.isLoggable(FLog.VERBOSE)) {
FLog.v(TAG, "controller %x %s: onDetach", System.identityHashCode(this), mId);
}
mEventTracker.recordEvent(Event.ON_DETACH_CONTROLLER);
mIsAttached = false;
mDeferredReleaser.scheduleDeferredRelease(this);
}
@Override
public boolean onTouchEvent(MotionEvent event) { // 回調(diào)
if (FLog.isLoggable(FLog.VERBOSE)) {
FLog.v(TAG, "controller %x %s: onTouchEvent %s", System.identityHashCode(this), mId, event);
}
if (mGestureDetector == null) {
return false;
}
if (mGestureDetector.isCapturingGesture() || shouldHandleGesture()) {
mGestureDetector.onTouchEvent(event);
return true;
}
return false;
}
/** Returns whether the gesture should be handled by the controller */
protected boolean shouldHandleGesture() {
return shouldRetryOnTap();
}
private boolean shouldRetryOnTap() {
// We should only handle touch event if we are expecting some gesture.
// For example, we expect click when fetch fails and tap-to-retry is enabled.
return mHasFetchFailed && mRetryManager != null && mRetryManager.shouldRetryOnTap(); // shouldRetryOnTap 判斷是否超過(guò)重新的最大值(MAX:4次)
}
@Override
public boolean onClick() {// 回調(diào)
if (FLog.isLoggable(FLog.VERBOSE)) {
FLog.v(TAG, "controller %x %s: onClick", System.identityHashCode(this), mId);
}
if (shouldRetryOnTap()) { // mRetryManager去通知重新request準(zhǔn)備
mRetryManager.notifyTapToRetry();
mSettableDraweeHierarchy.reset();
submitRequest();
return true;
}
return false;
}
protected void submitRequest() { // 這貨就是干活的
final T closeableImage = getCachedImage(); // 拿到子類的Cache圖片
if (closeableImage != null) { // 如果有将塑,直接刷新成功
mDataSource = null;
mIsRequestSubmitted = true;
mHasFetchFailed = false;
mEventTracker.recordEvent(Event.ON_SUBMIT_CACHE_HIT);
getControllerListener().onSubmit(mId, mCallerContext);
onNewResultInternal(mId, mDataSource, closeableImage, 1.0f, true, true);
return;
}
mEventTracker.recordEvent(Event.ON_DATASOURCE_SUBMIT); // 日志
getControllerListener().onSubmit(mId, mCallerContext); // 給監(jiān)聽(tīng)器去干活脉顿,一個(gè)id一個(gè)坑
mSettableDraweeHierarchy.setProgress(0, true);// 對(duì)象樹(shù)準(zhǔn)備
mIsRequestSubmitted = true;// 已經(jīng)提交
mHasFetchFailed = false;// 重置
mDataSource = getDataSource(); // 獲取子類data策略
if (FLog.isLoggable(FLog.VERBOSE)) {
FLog.v(
TAG,
"controller %x %s: submitRequest: dataSource: %x",
System.identityHashCode(this),
mId,
System.identityHashCode(mDataSource));
}
final String id = mId;
final boolean wasImmediate = mDataSource.hasResult();
final DataSubscriber<T> dataSubscriber =
new BaseDataSubscriber<T>() {
@Override
public void onNewResultImpl(DataSource<T> dataSource) {
// isFinished must be obtained before image, otherwise we might set intermediate result
// as final image.
boolean isFinished = dataSource.isFinished();
float progress = dataSource.getProgress();
T image = dataSource.getResult();
if (image != null) {
onNewResultInternal(id, dataSource, image, progress, isFinished, wasImmediate);
} else if (isFinished) {
onFailureInternal(id, dataSource, new NullPointerException(), /* isFinished */ true);
}
}
@Override
public void onFailureImpl(DataSource<T> dataSource) {
onFailureInternal(id, dataSource, dataSource.getFailureCause(), /* isFinished */ true);
}
@Override
public void onProgressUpdate(DataSource<T> dataSource) {
boolean isFinished = dataSource.isFinished();
float progress = dataSource.getProgress();
onProgressUpdateInternal(id, dataSource, progress, isFinished);
}
};
mDataSource.subscribe(dataSubscriber, mUiThreadImmediateExecutor); // 在ui線程訂閱,開(kāi)始刷新
}
private void onNewResultInternal( // 成功
String id,
DataSource<T> dataSource,
@Nullable T image,
float progress,
boolean isFinished,
boolean wasImmediate) {
// ignore late callbacks (data source that returned the new result is not the one we expected)
if (!isExpectedDataSource(id, dataSource)) { // 略過(guò)老data
logMessageAndImage("ignore_old_datasource @ onNewResult", image);
releaseImage(image);
dataSource.close();
return;
}
mEventTracker.recordEvent( // 日志追蹤
isFinished ? Event.ON_DATASOURCE_RESULT : Event.ON_DATASOURCE_RESULT_INT);
// create drawable
Drawable drawable;
try {
drawable = createDrawable(image); //調(diào)用子類策略創(chuàng)建drawable
} catch (Exception exception) { // 失敗打印和釋放資源
logMessageAndImage("drawable_failed @ onNewResult", image);
releaseImage(image);
onFailureInternal(id, dataSource, exception, isFinished);
return;
}
T previousImage = mFetchedImage; // 完成新老數(shù)據(jù)交換
Drawable previousDrawable = mDrawable;
mFetchedImage = image; // 給hold的當(dāng)前image進(jìn)行策略釋放
mDrawable = drawable;
try {
// set the new image
if (isFinished) { // 完成后点寥,刷新艾疟,監(jiān)聽(tīng)回掉,改干嘛干嘛
logMessageAndImage("set_final_result @ onNewResult", image);
mDataSource = null;
mSettableDraweeHierarchy.setImage(drawable, 1f, wasImmediate);
getControllerListener().onFinalImageSet(id, getImageInfo(image), getAnimatable());
// IMPORTANT: do not execute any instance-specific code after this point
} else {
logMessageAndImage("set_intermediate_result @ onNewResult", image);
mSettableDraweeHierarchy.setImage(drawable, progress, wasImmediate);
getControllerListener().onIntermediateImageSet(id, getImageInfo(image));
// IMPORTANT: do not execute any instance-specific code after this point
}
} finally { // 釋放當(dāng)前請(qǐng)求資源
if (previousDrawable != null && previousDrawable != drawable) {
releaseDrawable(previousDrawable);
}
if (previousImage != null && previousImage != image) {
logMessageAndImage("release_previous_result @ onNewResult", previousImage);
releaseImage(previousImage);
}
}
}
private void onFailureInternal( // 更新失敗數(shù)據(jù)
String id,
DataSource<T> dataSource,
Throwable throwable,
boolean isFinished) {
// ignore late callbacks (data source that failed is not the one we expected)
if (!isExpectedDataSource(id, dataSource)) { // 判斷是否是自己感興趣的data
logMessageAndFailure("ignore_old_datasource @ onFailure", throwable);
dataSource.close();
return;
}
mEventTracker.recordEvent( // 日志追蹤
isFinished ? Event.ON_DATASOURCE_FAILURE : Event.ON_DATASOURCE_FAILURE_INT);
// fail only if the data source is finished
if (isFinished) { //刷新失敗流程
logMessageAndFailure("final_failed @ onFailure", throwable);
mDataSource = null;
mHasFetchFailed = true;
// Set the previously available image if available.
if (mRetainImageOnFailure && mDrawable != null) {
mSettableDraweeHierarchy.setImage(mDrawable, 1f, true);
} else if (shouldRetryOnTap()) {
mSettableDraweeHierarchy.setRetry(throwable);
} else {
mSettableDraweeHierarchy.setFailure(throwable);
}
getControllerListener().onFailure(mId, throwable);
// IMPORTANT: do not execute any instance-specific code after this point
} else {
logMessageAndFailure("intermediate_failed @ onFailure", throwable);
getControllerListener().onIntermediateImageFailed(mId, throwable);
// IMPORTANT: do not execute any instance-specific code after this point
}
}
private void onProgressUpdateInternal( // 更新實(shí)時(shí)數(shù)據(jù)
String id,
DataSource<T> dataSource,
float progress,
boolean isFinished) {
// ignore late callbacks (data source that failed is not the one we expected)
if (!isExpectedDataSource(id, dataSource)) {
logMessageAndFailure("ignore_old_datasource @ onProgress", null);
dataSource.close();
return;
}
if (!isFinished) {
mSettableDraweeHierarchy.setProgress(progress, false);
}
}
private boolean isExpectedDataSource(String id, DataSource<T> dataSource) { // 判斷當(dāng)前提交狀態(tài)的dataSource 釋放為新的敢辩,持有id老dataSource 不再感興趣
if (dataSource == null && mDataSource == null) {
// DataSource is null when we use directly the Bitmap from the MemoryCache. In this case
// we don't have to close the DataSource.
return true;
}
// There are several situations in which an old data source might return a result that we are no
// longer interested in. To verify that the result is indeed expected, we check several things:
return id.equals(mId) && dataSource == mDataSource && mIsRequestSubmitted;
}
........
@Override
public @Nullable Animatable getAnimatable() {
return (mDrawable instanceof Animatable) ? (Animatable) mDrawable : null;
}
// 下面都是回掉子類接口 PipelineDraweeController
protected abstract DataSource<T> getDataSource();
protected abstract Drawable createDrawable(T image);
protected abstract @Nullable INFO getImageInfo(T image);
protected String getImageClass(@Nullable T image) {
return (image != null) ? image.getClass().getSimpleName() : "<null>";
}
protected int getImageHash(@Nullable T image) {
return System.identityHashCode(image);
}
protected abstract void releaseImage(@Nullable T image);
protected abstract void releaseDrawable(@Nullable Drawable drawable);
........
}
屬性:SettableDraweeHierarchy 你可以認(rèn)為這貨就是你的drawable的修飾類所需要維護(hù)的樹(shù)形結(jié)構(gòu)蔽莱,相當(dāng)于drawable是衣服的話,DraweeHierarchy就是衣服上的線條結(jié)構(gòu)和底色配色戚长,和XML中布局默認(rèn)屬性差不多
這個(gè)類比較長(zhǎng)盗冷,所有request是從attach開(kāi)始submit,onDetach停止和釋放資源維護(hù)同廉。
attach和onDetach事件來(lái)自于DraweeHierarchy中toplevel仪糖,Drawable的DraweeHold,它實(shí)現(xiàn)了監(jiān)聽(tīng)和派發(fā)回掉
好了你大致也看懂了submit這個(gè)函數(shù)中恤溶,先準(zhǔn)備一些flag乓诽,然后給Listener去實(shí)現(xiàn)submit,然后自己訂閱回掉在ui線程咒程,開(kāi)始刷新界面鸠天。
這個(gè)大多數(shù)人都有個(gè)誤區(qū),認(rèn)為L(zhǎng)istener是實(shí)現(xiàn)提交請(qǐng)求帐姻,其實(shí)不是稠集,這貨只是監(jiān)聽(tīng)回調(diào),真正在跑網(wǎng)絡(luò)數(shù)據(jù)得是這個(gè)訂閱得datasrouce,而這個(gè)datasrouce來(lái)自getDataSource(),這個(gè)來(lái)自AbstractDraweeControllerBuilder:getDataSourceSupplierForRequest(),一路追蹤最后來(lái)自PipelineDraweeControllerBuilder:getDataSourceForRequest(),好了這個(gè)主線來(lái)了饥瓷,ImagePipeline要開(kāi)始干活了剥纷,往上面翻,自己再總結(jié)理解下呢铆。
接著看:Fresco源碼分析(二)