Glide分析
發(fā)展到現(xiàn)在Android的圖片加載框架越來越成熟從一開始的UIL到后來的Glide、Picasso、fresco等。相比較而言Glide的功能更加強大,但是相應(yīng)的方法數(shù)也是最多的。當(dāng)然也得結(jié)合項目的需求還選擇相應(yīng)的框架。Glide比較吸引人的主要還是與Activity生命周期進(jìn)行綁定、加載gif圖片、可以配置相應(yīng)的網(wǎng)絡(luò)請求框架??赐瓯疚哪阋苍S會知道以下幾個問題:
glide如何加載圖片
glide如何加載gif
glide如何根據(jù)Activity的生命周期加載照片
glide如何解決listView圖片錯亂問題
glide的緩存策略
一、簡單用法
Glide.with(context).load("圖片url").into(imageView)
當(dāng)然這也是最簡單的用法,一行代碼就搞定了。比較詳細(xì)的用法可以點擊這個鏈接。
二、Glide的初始化
1、Glide.initializeGlide()
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
Context applicationContext = context.getApplicationContext();
//獲取使用注解自定義的AppGlideModule
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
//獲取在manifest文件中配置的AppGlideModule
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
manifestModules = new ManifestParser(applicationContext).parse();
}
//省略部分代碼...
//創(chuàng)建glide實例
Glide glide = builder.build(applicationContext);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.registerComponents(applicationContext, glide, glide.registry);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
applicationContext.registerComponentCallbacks(glide);
Glide.glide = glide;
}
這里首先會獲取自定義的AppGlideModule,然后在創(chuàng)建glide實例。這里的glide是個單例只會初始化一次。
2、GlideBuilder.bulid
Glide build(@NonNull Context context) {
//創(chuàng)建加載圖片線程池
if (sourceExecutor == null) {
sourceExecutor = GlideExecutor.newSourceExecutor();
}
//創(chuàng)建文件緩存線程池
if (diskCacheExecutor == null) {
diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
}
//創(chuàng)建加載圖片動畫線程池
if (animationExecutor == null) {
animationExecutor = GlideExecutor.newAnimationExecutor();
}
//根據(jù)設(shè)備獲取相應(yīng)的緩存大小
if (memorySizeCalculator == null) {
memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
}
//判斷是否獲取了網(wǎng)絡(luò)請求權(quán)限
if (connectivityMonitorFactory == null) {
connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
}
//獲取內(nèi)存緩存圖片池
if (bitmapPool == null) {
int size = memorySizeCalculator.getBitmapPoolSize();
if (size > 0) {
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
}
}
//對象池
if (arrayPool == null) {
arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
}
//內(nèi)存緩存
if (memoryCache == null) {
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
//磁盤緩存工廠類
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
//加載圖片引擎
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
GlideExecutor.newAnimationExecutor(),
isActiveResourceRetentionAllowed);
}
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions);
}
3、new Glide
Glide(
@NonNull Context context,
@NonNull Engine engine,
@NonNull MemoryCache memoryCache,
@NonNull BitmapPool bitmapPool,
@NonNull ArrayPool arrayPool,
@NonNull RequestManagerRetriever requestManagerRetriever,
@NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
int logLevel,
@NonNull RequestOptions defaultRequestOptions,
@NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions) {
this.engine = engine;
this.bitmapPool = bitmapPool;
this.arrayPool = arrayPool;
this.memoryCache = memoryCache;
this.requestManagerRetriever = requestManagerRetriever;
this.connectivityMonitorFactory = connectivityMonitorFactory;
//解碼格式
DecodeFormat decodeFormat = defaultRequestOptions.getOptions().get(Downsampler.DECODE_FORMAT);
bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat);
final Resources resources = context.getResources();
registry = new Registry();
//注冊文件頭解析類
registry.register(new DefaultImageHeaderParser());
Downsampler downsampler = new Downsampler(registry.getImageHeaderParsers(),
resources.getDisplayMetrics(), bitmapPool, arrayPool);
//解碼類:將InputStream中解碼成GIF
ByteBufferGifDecoder byteBufferGifDecoder =
new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), bitmapPool, arrayPool);
//解碼類:將Video中解碼成bitmap
ResourceDecoder<ParcelFileDescriptor, Bitmap> parcelFileDescriptorVideoDecoder =
VideoDecoder.parcel(bitmapPool);
//解碼類:將ByteBuffer解碼成bitmap
ByteBufferBitmapDecoder byteBufferBitmapDecoder = new ByteBufferBitmapDecoder(downsampler);
//解碼類:將InputStreams解碼成bitmap
StreamBitmapDecoder streamBitmapDecoder = new StreamBitmapDecoder(downsampler, arrayPool);
//解碼類:通過Uri解碼成Drawable
ResourceDrawableDecoder resourceDrawableDecoder =
new ResourceDrawableDecoder(context);
//解碼類:將資源文件轉(zhuǎn)換成InputStream
ResourceLoader.StreamFactory resourceLoaderStreamFactory =
new ResourceLoader.StreamFactory(resources);
//將資源文件轉(zhuǎn)換成URI
ResourceLoader.UriFactory resourceLoaderUriFactory =
new ResourceLoader.UriFactory(resources);
//將資源文件轉(zhuǎn)換成ParcelFileDescriptor
ResourceLoader.FileDescriptorFactory resourceLoaderFileDescriptorFactory =
new ResourceLoader.FileDescriptorFactory(resources);
//將資源文件轉(zhuǎn)換成ParcelFileDescriptor
ResourceLoader.AssetFileDescriptorFactory resourceLoaderAssetFileDescriptorFactory =
new ResourceLoader.AssetFileDescriptorFactory(resources);
//Bitmap解碼類
BitmapEncoder bitmapEncoder = new BitmapEncoder(arrayPool);
//bitmap轉(zhuǎn)btye[]類
BitmapBytesTranscoder bitmapBytesTranscoder = new BitmapBytesTranscoder();
//GifDrawable轉(zhuǎn)btye[]類
GifDrawableBytesTranscoder gifDrawableBytesTranscoder = new GifDrawableBytesTranscoder();
ContentResolver contentResolver = context.getContentResolver();
registry
.append(ByteBuffer.class, new ByteBufferEncoder())
.append(InputStream.class, new StreamEncoder(arrayPool))
//添加轉(zhuǎn)換成Bitmap相應(yīng)解碼類
.append(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class, byteBufferBitmapDecoder)
.append(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, streamBitmapDecoder)
.append(
Registry.BUCKET_BITMAP,
ParcelFileDescriptor.class,
Bitmap.class,
parcelFileDescriptorVideoDecoder)
.append(
Registry.BUCKET_BITMAP,
AssetFileDescriptor.class,
Bitmap.class,
VideoDecoder.asset(bitmapPool))
.append(Bitmap.class, Bitmap.class, UnitModelLoader.Factory.<Bitmap>getInstance())
.append(
Registry.BUCKET_BITMAP, Bitmap.class, Bitmap.class, new UnitBitmapDecoder())
.append(Bitmap.class, bitmapEncoder)
//添加轉(zhuǎn)換成BitmapDrawables相應(yīng)解碼類
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
ByteBuffer.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, byteBufferBitmapDecoder))
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
InputStream.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, streamBitmapDecoder))
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
ParcelFileDescriptor.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, parcelFileDescriptorVideoDecoder))
.append(BitmapDrawable.class, new BitmapDrawableEncoder(bitmapPool, bitmapEncoder))
//添加轉(zhuǎn)換成GIFs相應(yīng)解碼類
.append(
Registry.BUCKET_GIF,
InputStream.class,
GifDrawable.class,
new StreamGifDecoder(registry.getImageHeaderParsers(), byteBufferGifDecoder, arrayPool))
.append(Registry.BUCKET_GIF, ByteBuffer.class, GifDrawable.class, byteBufferGifDecoder)
.append(GifDrawable.class, new GifDrawableEncoder())
/* GIF Frames */
// Compilation with Gradle requires the type to be specified for UnitModelLoader here.
//添加將GIFs解碼成Bitmap
.append(
GifDecoder.class, GifDecoder.class, UnitModelLoader.Factory.<GifDecoder>getInstance())
.append(
Registry.BUCKET_BITMAP,
GifDecoder.class,
Bitmap.class,
new GifFrameResourceDecoder(bitmapPool))
//添加轉(zhuǎn)換成Drawables相應(yīng)解碼類
.append(Uri.class, Drawable.class, resourceDrawableDecoder)
.append(
Uri.class, Bitmap.class, new ResourceBitmapDecoder(resourceDrawableDecoder, bitmapPool))
//添加文件處理類
.register(new ByteBufferRewinder.Factory())
.append(File.class, ByteBuffer.class, new ByteBufferFileLoader.Factory())
.append(File.class, InputStream.class, new FileLoader.StreamFactory())
.append(File.class, File.class, new FileDecoder())
.append(File.class, ParcelFileDescriptor.class, new FileLoader.FileDescriptorFactory())
// Compilation with Gradle requires the type to be specified for UnitModelLoader here.
.append(File.class, File.class, UnitModelLoader.Factory.<File>getInstance())
//添加轉(zhuǎn)換類(將任意復(fù)雜的數(shù)據(jù)模型轉(zhuǎn)化為一個具體的數(shù)據(jù)類型,然后通過DataFetcher處理得到相應(yīng)的可用資源)
.register(new InputStreamRewinder.Factory(arrayPool))
//通過資源文件轉(zhuǎn)化成InputStream
.append(int.class, InputStream.class, resourceLoaderStreamFactory)
//通過資源文件轉(zhuǎn)化成ParcelFileDescriptor
.append(
int.class,
ParcelFileDescriptor.class,
resourceLoaderFileDescriptorFactory)
.append(Integer.class, InputStream.class, resourceLoaderStreamFactory)
.append(
Integer.class,
ParcelFileDescriptor.class,
resourceLoaderFileDescriptorFactory)
//通過資源文件轉(zhuǎn)化成Uri
.append(Integer.class, Uri.class, resourceLoaderUriFactory)
.append(
int.class,
AssetFileDescriptor.class,
resourceLoaderAssetFileDescriptorFactory)
.append(
Integer.class,
AssetFileDescriptor.class,
resourceLoaderAssetFileDescriptorFactory)
.append(int.class, Uri.class, resourceLoaderUriFactory)
//通過字符串轉(zhuǎn)化成InputStream
.append(String.class, InputStream.class, new DataUrlLoader.StreamFactory<String>())
//通過Uri轉(zhuǎn)化成InputStream
.append(Uri.class, InputStream.class, new DataUrlLoader.StreamFactory<Uri>())
//通過String轉(zhuǎn)化成InputStream
.append(String.class, InputStream.class, new StringLoader.StreamFactory())
//通過String轉(zhuǎn)化成ParcelFileDescriptor
.append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
//通過String轉(zhuǎn)化成AssetFileDescriptor
.append(
String.class, AssetFileDescriptor.class, new StringLoader.AssetFileDescriptorFactory())
//通過網(wǎng)絡(luò)Uri轉(zhuǎn)化成InputStream
.append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
//通過資產(chǎn)目錄Uri轉(zhuǎn)化成InputStream
.append(Uri.class, InputStream.class, new AssetUriLoader.StreamFactory(context.getAssets()))
//通過Uri轉(zhuǎn)化成ParcelFileDescriptor
.append(
Uri.class,
ParcelFileDescriptor.class,
new AssetUriLoader.FileDescriptorFactory(context.getAssets()))
//通過image Uri轉(zhuǎn)化成InputStream
.append(Uri.class, InputStream.class, new MediaStoreImageThumbLoader.Factory(context))
//通過video Uri轉(zhuǎn)化成InputStream
.append(Uri.class, InputStream.class, new MediaStoreVideoThumbLoader.Factory(context))
//通過Uri轉(zhuǎn)化成InputStream
.append(
Uri.class,
InputStream.class,
new UriLoader.StreamFactory(contentResolver))
//通過Uri轉(zhuǎn)化成ParcelFileDescriptor
.append(
Uri.class,
ParcelFileDescriptor.class,
new UriLoader.FileDescriptorFactory(contentResolver))
//通過Uri轉(zhuǎn)化成AssetFileDescriptor
.append(
Uri.class,
AssetFileDescriptor.class,
new UriLoader.AssetFileDescriptorFactory(contentResolver))
//通過http/https Uris轉(zhuǎn)化成InputStream
.append(Uri.class, InputStream.class, new UrlUriLoader.StreamFactory())
//通過 java.net.URL轉(zhuǎn)化成InputStream
.append(URL.class, InputStream.class, new UrlLoader.StreamFactory())
//通過多媒體文件uri轉(zhuǎn)化成文件
.append(Uri.class, File.class, new MediaStoreFileLoader.Factory(context))
//通過http/https url轉(zhuǎn)化成InputStream
.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
//通過數(shù)組轉(zhuǎn)化成ByteBuffer
.append(byte[].class, ByteBuffer.class, new ByteArrayLoader.ByteBufferFactory())
//通過數(shù)組轉(zhuǎn)化成InputStream
.append(byte[].class, InputStream.class, new ByteArrayLoader.StreamFactory())
.append(Uri.class, Uri.class, UnitModelLoader.Factory.<Uri>getInstance())
.append(Drawable.class, Drawable.class, UnitModelLoader.Factory.<Drawable>getInstance())
.append(Drawable.class, Drawable.class, new UnitDrawableDecoder())
//注冊轉(zhuǎn)碼類
//bitmap轉(zhuǎn)碼成BitmapDrawable
.register(
Bitmap.class,
BitmapDrawable.class,
new BitmapDrawableTranscoder(resources))
//bitmap轉(zhuǎn)碼成byte[]
.register(Bitmap.class, byte[].class, bitmapBytesTranscoder)
//Drawable轉(zhuǎn)碼成byte[]
.register(
Drawable.class,
byte[].class,
new DrawableBytesTranscoder(
bitmapPool, bitmapBytesTranscoder, gifDrawableBytesTranscoder))
//GifDrawable轉(zhuǎn)碼成byte[]
.register(GifDrawable.class, byte[].class, gifDrawableBytesTranscoder);
ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
glideContext =
new GlideContext(
context,
arrayPool,
registry,
imageViewTargetFactory,
defaultRequestOptions,
defaultTransitionOptions,
engine,
logLevel);
}
glide的初始化話還是比較復(fù)雜的,主要就是配置相應(yīng)的設(shè)置和加載注冊將相應(yīng)的數(shù)量類型轉(zhuǎn)換成可用的數(shù)據(jù)。至此glide的初始化就完成了。
三、加載圖片
初始化完之后就開始加載圖片了,調(diào)用with方法就會創(chuàng)建一個RequestManager,這里以with(Activity)為例:
1、創(chuàng)建RequestManager
1.1、Glide.with()
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
這里獲取初始化Glide時設(shè)置的RequestManagerRetriever:
public RequestManager get(@NonNull Activity activity) {
//判斷當(dāng)前線程是否是主線程
if (Util.isOnBackgroundThread()) {
//如果不在主線程中否則則創(chuàng)建一個綁定application生命周期的RequestManager
return get(activity.getApplicationContext());
} else {
//排查當(dāng)前Activity沒有被銷毀
assertNotDestroyed(activity);
//獲取fragmentManager
android.app.FragmentManager fm = activity.getFragmentManager();
//創(chuàng)建一個與fragment生命周期綁定的RequestManager(RequestManager實現(xiàn)了LifecycleListener接口
//并將自己添加到了RequestManagerFragment的ActivityFragmentLifecycle隊列中,
//當(dāng)RequestManagerFragment執(zhí)行生命周期方法時就會調(diào)用LifecycleListener接口實現(xiàn)類,
//從而做出相應(yīng)的處理暫停請求或移除請求)
return fragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
1.2、RequestManagerRetriever.fragmentGet()
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
//創(chuàng)建一個RequestManagerFragment并添加到當(dāng)前Activity中
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
//判斷與其fragment綁定的RequestManager是否已經(jīng)創(chuàng)建,否則則創(chuàng)建
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
2、創(chuàng)建RequestBuilder
2.1、RequestManager.load()
這里以字符串為參數(shù),因為沒有設(shè)置將對應(yīng)資源轉(zhuǎn)成具體的數(shù)據(jù)類型(bitmap、GIF、drawable),所以會默認(rèn)轉(zhuǎn)換成drawable。
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
RequestManager.asDrawable()->
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
RequestManager.as()->
創(chuàng)建RequestBuilder實例
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
2.2、RequestBuilder.load()
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
3、加載圖片
3.1構(gòu)建請求
3.1.1、RequestBuilder.into()
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
//確保是在主線程中運行
Util.assertMainThread();
//檢測當(dāng)前ImageView是否為null
Preconditions.checkNotNull(view);
//配置請求 設(shè)置圖片的縮放類型(ImageView 默認(rèn)是FIT_CENTER)
RequestOptions requestOptions = this.requestOptions;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions);
}
3.1.2、glideContext.buildImageViewTarget(view, transcodeClass)
ImageViewTargetFactory.buildTarget:
public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
@NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
//作為Bitmap加載
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
//作為Drawable加載
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
根據(jù)相應(yīng)想要加載類型返回ViewTarget。
3.1.3、RequestBuilder.into( Y target,RequestListener<TranscodeType> targetListener,RequestOptions options)
@NonNull
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
@NonNull RequestOptions options) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
//判斷是否調(diào)用了load方法
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//克隆一份請求設(shè)置,因為得保證每一個ImageView對應(yīng)一個options
options = options.autoClone();
//創(chuàng)建請求 見3.1.4
Request request = buildRequest(target, targetListener, options);
//獲取當(dāng)前ImageView對應(yīng)的請求
Request previous = target.getRequest();
//若當(dāng)前ImageView對應(yīng)的請求已經(jīng)設(shè)置(即為ImageView設(shè)置了tag)
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
//先清除當(dāng)前View的tag
requestManager.clear(target);
//設(shè)置當(dāng)前View tag(即setTag)
target.setRequest(request);
//添加執(zhí)行request
requestManager.track(target, request);
return target;
}
3.1.4、RequestBuilder.buildRequest()
->RequestBuilder.buildRequestRecursive():
private Request buildRequestRecursive(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
RequestOptions requestOptions) {
// Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
ErrorRequestCoordinator errorRequestCoordinator = null;
//判斷是否設(shè)置了當(dāng)前請求錯誤的錯誤請求
if (errorBuilder != null) {
errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
//構(gòu)建請求(這里會根據(jù)是否設(shè)置了獲取縮略圖請求或縮略比例來創(chuàng)建SingleRequest。這里SingleRequest是從SingleRequestPool中獲取的 詳見SingleRequest類)
Request mainRequest =
buildThumbnailRequestRecursive(
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions);
//沒有設(shè)置錯誤時的錯誤請求時則直接返回正常請求
if (errorRequestCoordinator == null) {
return mainRequest;
}
//省略部分代碼
Request errorRequest = errorBuilder.buildRequestRecursive(
target,
targetListener,
errorRequestCoordinator,
errorBuilder.transitionOptions,
errorBuilder.requestOptions.getPriority(),
errorOverrideWidth,
errorOverrideHeight,
errorBuilder.requestOptions);
//設(shè)置錯誤時的錯誤請求時則添加errorRequest
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
3.2、執(zhí)行請求
至此請求就已經(jīng)構(gòu)建好了,接下來就是執(zhí)行請求了。
3.2.1、RequestManager.track()
void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
3.2.2、TargetTracker.track()
public void track(@NonNull Target<?> target) {
targets.add(target);
}
因為TargetTracker實現(xiàn)了LifecycleListener,當(dāng)回調(diào)RequestManager的生命周期方法時同時也會執(zhí)行TargetTracker的相對應(yīng)方法。
3.2.2、requestTracker.runRequest()
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
這里比較簡單主要就是先判斷是否進(jìn)入了Paused狀態(tài),若沒有則直接開始請求,若處于Paused狀態(tài)時則加入到等待請求隊列中。這里的ruquest是在3.1.4創(chuàng)建的SingleRequest。
3.2.3、SingleRequest.begin()
@Override
public void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
//判斷加載的內(nèi)容模型是否為空
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
//當(dāng)前請求正在執(zhí)行中...
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
//當(dāng)前請求已經(jīng)執(zhí)行完成
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
//設(shè)置請求圖片的寬高
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
//開始請求
onSizeReady(overrideWidth, overrideHeight);
} else {
//獲取當(dāng)前View的寬高之后 再調(diào)用onSizeReady方法
target.getSize(this);
}
//正在請求時 設(shè)置PlaceholderDrawable圖片
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
}
3.2.4、SingleRequest.onSizeReady()
-->Engine.load()
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb) {
Util.assertMainThread();
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
//更新相應(yīng)屬性創(chuàng)建EngineKey
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//嘗試從活躍的資源內(nèi)存緩存中中獲取
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
//嘗試從內(nèi)存緩存中獲取
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
//判斷當(dāng)前請求是在在隊列中
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
//創(chuàng)建請求job
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
//創(chuàng)建解碼job
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
//保存當(dāng)前請求job
jobs.put(key, engineJob);
engineJob.addCallback(cb);
//開始請求
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);
}
3.2.5、EngineJob.start()
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
DecodeJob實現(xiàn)了Runnable接口,這里將其添加到線程池中。接下來看下run方法 。
3.2.5、DecodeJob.run()
@Override
public void run() {
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
DataFetcher<?> localFetcher = currentFetcher;
try {
//判斷是否已經(jīng)被取消
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
} catch (Throwable t) {
if (stage != Stage.ENCODE) {
throwables.add(t);
notifyFailed();
}
if (!isCancelled) {
throw t;
}
} finally {
if (localFetcher != null) {
localFetcher.cleanup();
}
GlideTrace.endSection();
}
}
3.2.6、DecodeJob.runWrapped()
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
//根據(jù)當(dāng)前流程步驟獲取相應(yīng)獲取數(shù)據(jù)類(剛開始肯定為INITIALIZE初始化狀態(tài))
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
3.2.7、DecodeJob.getNextGenerator()
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
//從內(nèi)存緩存中獲取
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
//從文件緩存中獲取
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
//從相應(yīng)的資源中獲取
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
3.2.8、DecodeJob.runGenerators()
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
//依次從內(nèi)存、文件及相應(yīng)資源中獲取。
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
這里會依次從文件緩存、相應(yīng)資源(比如網(wǎng)絡(luò)、uri等)處獲取圖片。因為是圖片是第一次加載,所以接下來我們看下SourceGenerator的startNext()方法。
3.2.9、SourceGenerator.startNext()
public boolean startNext() {
//判斷當(dāng)前請求是否成功,成了調(diào)用DataCacheGenerator的next方法,從而生成相應(yīng)的圖片
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
//依次從注冊了處理該資源的實例
while (!started && hasNextModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
//開始加載資源
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
這里會從registry中匹配相應(yīng)的Modeloader來加載數(shù)據(jù)。這里是HttpUrlFetcher。
3.2.10、HttpUrlFetcher.loadData()
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
//連接網(wǎng)絡(luò)獲取圖片流
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
//成功回調(diào)
callback.onDataReady(result);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to load data for url", e);
}
callback.onLoadFailed(e);
} finally {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
}
}
}
請求成功之后回調(diào)了DataCallback方法。最終會回調(diào)到DecodeJob的onDataFetcherReady方法,之后在進(jìn)行解碼操作:
private void decodeFromRetrievedData() {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Retrieved data", startFetchTime,
"data: " + currentData
+ ", cache key: " + currentSourceKey
+ ", fetcher: " + currentFetcher);
}
Resource<R> resource = null;
try {
//進(jìn)行解碼(從registery中匹配相應(yīng)的解碼實例類Downsampler進(jìn)行解碼)
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
//解碼成功
notifyEncodeAndRelease(resource, currentDataSource);
} else {
//解碼失敗進(jìn)行下一步操作
runGenerators();
}
}
解碼成功之后,回調(diào)EngineJob中的onResourceReady方法:
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
this.resource = resource;
this.dataSource = dataSource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
通過handler切換至主線程
private static class MainThreadCallback implements Handler.Callback {
@Synthetic
@SuppressWarnings("WeakerAccess")
MainThreadCallback() { }
@Override
public boolean handleMessage(Message message) {
EngineJob<?> job = (EngineJob<?>) message.obj;
switch (message.what) {
case MSG_COMPLETE:
job.handleResultOnMainThread();
break;
case MSG_EXCEPTION:
job.handleExceptionOnMainThread();
break;
case MSG_CANCELLED:
job.handleCancelledOnMainThread();
break;
default:
throw new IllegalStateException("Unrecognized message: " + message.what);
}
return true;
}
}
3.2.11、EngineJob.handleResultOnMainThread()
@Synthetic
void handleResultOnMainThread() {
stateVerifier.throwIfRecycled();
if (isCancelled) {
resource.recycle();
release(false /*isRemovedFromQueue*/);
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received a resource without any callbacks to notify");
} else if (hasResource) {
throw new IllegalStateException("Already have resource");
}
engineResource = engineResourceFactory.build(resource, isCacheable);
hasResource = true;
// Hold on to resource for duration of request so we don't recycle it in the middle of
// notifying if it synchronously released by one of the callbacks.
engineResource.acquire();
listener.onEngineJobComplete(this, key, engineResource);
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0, size = cbs.size(); i < size; i++) {
ResourceCallback cb = cbs.get(i);
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
cb.onResourceReady(engineResource, dataSource);
}
}
// Our request is complete, so we can release the resource.
engineResource.release();
release(false /*isRemovedFromQueue*/);
}
將Bitmap設(shè)置給ViewImage。至此就完成了一張圖片的加載。
四、加載GIF
不管是加載Bitmap、Drawable還是Gif,解碼成功并轉(zhuǎn)化成相應(yīng)的Resource之后都會調(diào)用SingleRequest.onResourceReady()。
1、SingleRequest.onResourceReady()
private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
isCallingCallbacks = true;
try {
//是否設(shè)置了加載成功的監(jiān)聽并且判斷返回值是否為true
if ((requestListener == null
|| !requestListener.onResourceReady(result, model, target, dataSource, isFirstResource))
&& (targetListener == null
|| !targetListener.onResourceReady(result, model, target, dataSource, isFirstResource))) {
//加載動畫
Transition<? super R> animation =
animationFactory.build(dataSource, isFirstResource);
//為target設(shè)置值
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
//通知加載成功
notifyLoadSuccess();
}
2、DrawableImageViewTarget.onResourceReady()
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
//給ImageView設(shè)置drawable(相當(dāng)于是gif的第一幀圖片)
setResourceInternal(resource);
} else {
//開始GIF動畫
maybeUpdateAnimatable(resource);
}
}
這里我們看的是加載GIF,所以我們重點看下gif相關(guān)的兩個重點類GifDrawable和GifFrameLoader。
2、GifDrawable.start()
public void start() {
isStarted = true;
resetLoopCount();
if (isVisible) {
startRunning();
}
}
開始動畫
private void startRunning() {
Preconditions.checkArgument(!isRecycled, "You cannot start a recycled Drawable. Ensure that"
+ "you clear any references to the Drawable when clearing the corresponding request.");
if (state.frameLoader.getFrameCount() == 1) {
invalidateSelf();
} else if (!isRunning) {
isRunning = true;
//訂閱GifFrameLoader切換下一幀圖片事件
state.frameLoader.subscribe(this);
invalidateSelf();
}
}
2、GifFrameLoader.start()
private void start() {
if (isRunning) {
return;
}
isRunning = true;
isCleared = false;
loadNextFrame();
}
GifFrameLoader.loadNextFrame():
private void loadNextFrame() {
if (!isRunning || isLoadPending) {
return;
}
if (startFromFirstFrame) {
Preconditions.checkArgument(
pendingTarget == null, "Pending target must be null when starting from the first frame");
gifDecoder.resetFrameIndex();
startFromFirstFrame = false;
}
if (pendingTarget != null) {
DelayTarget temp = pendingTarget;
pendingTarget = null;
onFrameReady(temp);
return;
}
isLoadPending = true;
int delay = gifDecoder.getNextDelay();
long targetTime = SystemClock.uptimeMillis() + delay;
gifDecoder.advance();
next = new DelayTarget(handler, gifDecoder.getCurrentFrameIndex(), targetTime);
//繼續(xù)加載下一幀圖片,加載成功之后一樣的會調(diào)用 DelayTarget的onResourceReady方法
requestBuilder.apply(signatureOf(getFrameSignature())).load(gifDecoder).into(next);
}
3、DelayTarget.onResourceReady()
@Override
public void onResourceReady(@NonNull Bitmap resource,
@Nullable Transition<? super Bitmap> transition) {
this.resource = resource;
Message msg = handler.obtainMessage(FrameLoaderCallback.MSG_DELAY, this);
handler.sendMessageAtTime(msg, targetTime);
}
這里的handle是GifFrameLoader中設(shè)置的handler,我們看下是如何處理這個消息的:
@Override
public boolean handleMessage(Message msg) {
if (msg.what == MSG_DELAY) {
GifFrameLoader.DelayTarget target = (DelayTarget) msg.obj;
onFrameReady(target);
return true;
} else if (msg.what == MSG_CLEAR) {
GifFrameLoader.DelayTarget target = (DelayTarget) msg.obj;
requestManager.clear(target);
}
return false;
}
這里又回調(diào)了GifFrameLoader中的onFrameReady方法
3、GifFrameLoader. onFrameReady()
@VisibleForTesting
void onFrameReady(DelayTarget delayTarget) {
if (onEveryFrameListener != null) {
onEveryFrameListener.onFrameReady();
}
isLoadPending = false;
//如果取消了則停止更新imageView的drawable
if (isCleared) {
handler.obtainMessage(FrameLoaderCallback.MSG_CLEAR, delayTarget).sendToTarget();
return;
}
if (!isRunning) {
pendingTarget = delayTarget;
return;
}
if (delayTarget.getResource() != null) {
//回收上一幀圖片
recycleFirstFrame();
DelayTarget previous = current;
//將加載好的圖片賦值給當(dāng)前需要加載的圖片
current = delayTarget;
for (int i = callbacks.size() - 1; i >= 0; i--) {
FrameCallback cb = callbacks.get(i);
//刷新給imageView設(shè)置的drawable
cb.onFrameReady();
}
if (previous != null) {
handler.obtainMessage(FrameLoaderCallback.MSG_CLEAR, previous).sendToTarget();
}
}
//接著進(jìn)行下一幀圖片的加載(然后又會從新執(zhí)行這個方法,如此循環(huán)往復(fù))
loadNextFrame();
}
至此我們就知道了Glide加載Gif圖片的原理了,就是將gif根據(jù)每一幀解析成很張圖片,然后在依次設(shè)置給ImageView。
五、總結(jié)
1、Glide實現(xiàn)了內(nèi)存緩存和磁盤緩存,且都設(shè)置了相應(yīng)的大小,并根據(jù)lrus算法進(jìn)行更新和刪除。
2、Glide將加載了的圖片添加到Map(Key, ResourceWeakReference)中實現(xiàn)內(nèi)存緩存。
3、Glide的加載順序是先從內(nèi)存中獲取,若沒有則從磁盤中獲取,在沒有則通過網(wǎng)絡(luò)獲取。從網(wǎng)絡(luò)上獲取到了圖片之后若設(shè)置了可緩存,則會緩存到磁盤中;然后在通過相應(yīng)的加載參數(shù)進(jìn)行解碼壓縮裁剪等操作之后得到圖片設(shè)置給ImageView,同時緩存到內(nèi)存中。
4、Glide通過為當(dāng)前Activity添加一個fragment來監(jiān)聽相應(yīng)的生命周期方法,從而實現(xiàn)加載與Activity生命周期綁定,onstart時進(jìn)行加載、onstop時停止加載等。
5、Glide在開始加載圖片時,會給當(dāng)前ViewTarget設(shè)置對應(yīng)的Request,同時也會ViewTarget中的View設(shè)置tag為Request。在listView復(fù)用時有了這個Tag值,從而解決錯亂的問題