coil源码流程分析
先看简单使用
iv_image.load(
"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=80737749,1866961412&fm=26&gp=0.jpg"
) {
}
直接使用imageview 的拓展函数加载图片,点进去:
@JvmSynthetic
inline fun ImageView.load(
uri: String?,
imageLoader: ImageLoader = context.imageLoader,
builder: ImageRequest.Builder.() -> Unit = {}
): Disposable = loadAny(uri, imageLoader, builder)
@JvmSynthetic
inline fun ImageView.loadAny(
data: Any?,
imageLoader: ImageLoader = context.imageLoader,
builder: ImageRequest.Builder.() -> Unit = {}
): Disposable {
val request = ImageRequest.Builder(context)
.data(data)
.target(this)
.apply(builder)
.build()
return imageLoader.enqueue(request)
}
最后走到loadAny 方法中,这里需要注意的是data为string 类型,tatget 为ImageViewTarget,ImageViewTarget持有imageView的引用。
通过builder 的方式构建一个request,用enqueue方法执行,其中imageLoader为RealImageLoader对象
inline val Context.imageLoader: ImageLoader
@JvmName("imageLoader") get() = Coil.imageLoader(this)
@JvmStatic
fun imageLoader(context: Context): ImageLoader = imageLoader ?: newImageLoader(context)
@Synchronized
private fun newImageLoader(context: Context): ImageLoader {
// Check again in case imageLoader was just set.
imageLoader?.let { return it }
// Create a new ImageLoader.
val newImageLoader = imageLoaderFactory?.newImageLoader()
?: (context.applicationContext as? ImageLoaderFactory)?.newImageLoader()
?: ImageLoader(context)
imageLoaderFactory = null
imageLoader = newImageLoader
return newImageLoader
}
companion object {
/** Create a new [ImageLoader] without configuration. */
@JvmStatic
@JvmName("create")
operator fun invoke(context: Context) = Builder(context).build()
}
fun build(): ImageLoader {
//.....
return RealImageLoader(
context = applicationContext,
defaults = defaults,
bitmapPool = bitmapPool,
referenceCounter = referenceCounter,
strongMemoryCache = strongMemoryCache,
weakMemoryCache = weakMemoryCache,
callFactory = callFactory ?: buildDefaultCallFactory(),
eventListenerFactory = eventListenerFactory ?: EventListener.Factory.NONE,
componentRegistry = registry ?: ComponentRegistry(),
addLastModifiedToFileCacheKey = addLastModifiedToFileCacheKey,
launchInterceptorChainOnMainThread = launchInterceptorChainOnMainThread,
logger = logger
)
}
进去进入看RealImageLoader.enqueue 方法
override fun enqueue(request: ImageRequest): Disposable {
// Start executing the request on the main thread.
//这个应该是协程,不过是运行在主线程中的
val job = scope.launch {
//执行
val result = executeMain(request, REQUEST_TYPE_ENQUEUE)
if (result is ErrorResult) throw result.throwable
}
// Update the current request attached to the view and return a new disposable.
return if (request.target is ViewTarget<*>) {
val requestId = request.target.view.requestManager.setCurrentRequestJob(job)
ViewTargetDisposable(requestId, request.target)
} else {
BaseTargetDisposable(job)
}
}
继续往下,看executeMain 方法
@MainThread
private suspend fun executeMain(initialRequest: ImageRequest, type: Int): ImageResult {
// Ensure this image loader isn't shutdown.
//判断是否停止
check(!isShutdown.get()) { "The image loader is shutdown." }
// Apply this image loader's defaults to this request.
//创建一个新的request
val request = initialRequest.newBuilder().defaults(defaults).build()
// Create a new event listener.
//创建回调监听
val eventListener = eventListenerFactory.create(request)
// Wrap the target to support bitmap pooling.
//创建请求回调监听,用于得到请求结果时设置图片
val targetDelegate = delegateService.createTargetDelegate(request.target, type, eventListener)
// Wrap the request to manage its lifecycle.
//创建lifecycle监听
val requestDelegate = delegateService.createRequestDelegate(request, targetDelegate, coroutineContext.job)
try {
// Fail before starting if data is null.
//检查data
if (request.data == NullRequestData) throw NullRequestDataException()
// Enqueued requests suspend until the lifecycle is started.
//检查生命周期
if (type == REQUEST_TYPE_ENQUEUE) request.lifecycle.awaitStarted()
// Set the placeholder on the target.
//设置占位图
val cached = memoryCacheService[request.placeholderMemoryCacheKey]?.bitmap
try {
targetDelegate.metadata = null
// targetDelegate 就是 ImageViewTarget 对象, 调用onStart 方法,设置对应的占位图
targetDelegate.start(cached?.toDrawable(request.context) ?: request.placeholder, cached)
eventListener.onStart(request)
request.listener?.onStart(request)
} finally {
referenceCounter.decrement(cached)
}
// Resolve the size.
//计算宽高
eventListener.resolveSizeStart(request)
val size = request.sizeResolver.size()
eventListener.resolveSizeEnd(request, size)
// Execute the interceptor chain.
//执行,得到结果
val result = executeChain(request, type, size, cached, eventListener)
// Set the result on the target.
//判断请求结果,设置成功失败
when (result) {
is SuccessResult -> onSuccess(result, targetDelegate, eventListener)
is ErrorResult -> onError(result, targetDelegate, eventListener)
}
return result
} catch (throwable: Throwable) {
if (throwable is CancellationException) {
onCancel(request, eventListener)
throw throwable
} else {
// Create the default error result if there's an uncaught exception.
val result = requestService.errorResult(request, throwable)
onError(result, targetDelegate, eventListener)
return result
}
} finally {
requestDelegate.complete()
}
}
接下来走到executeChain方法中,executeChain方法看着就像okhttp的责任链
private suspend inline fun executeChain(
request: ImageRequest,
type: Int,
size: Size,
cached: Bitmap?,
eventListener: EventListener
): ImageResult {
//很明显,okhttp 方式的责任链,看对应的interceptors
val chain = RealInterceptorChain(request, type, interceptors, 0, request, size, cached, eventListener)
return if (launchInterceptorChainOnMainThread) {
chain.proceed(request)
} else {
withContext(request.dispatcher) {
chain.proceed(request)
}
}
}
很明显,就是使用okhttp的责任链方式,请求拦截,其中interceptors的值为
//在 RealImageLoader 最顶部初始化,先走registry中的interceptors,然后走EngineInterceptor
private val interceptors = registry.interceptors + EngineInterceptor(registry, bitmapPool, referenceCounter,
strongMemoryCache, memoryCacheService, requestService, systemCallbacks, drawableDecoder, logger)
走到EngineInterceptor 中的intercept 方法中
override suspend fun intercept(chain: Interceptor.Chain): ImageResult {
try {
// This interceptor uses some internal APIs.
check(chain is RealInterceptorChain)
//获取对应的数据
val request = chain.request
val context = request.context
val data = request.data
val size = chain.size
val eventListener = chain.eventListener
// Perform any data mapping.
eventListener.mapStart(request, data)
//转换,将string 类型的data转换成Uri类型
val mappedData = registry.mapData(data)
eventListener.mapEnd(request, mappedData)
// Check the memory cache.
//获取可以处理这次请求的fetcher ,这里只是获取,没有实际获取
val fetcher = request.fetcher(mappedData) ?: registry.requireFetcher(mappedData)
//获取内存缓存的key
val memoryCacheKey = request.memoryCacheKey ?: computeMemoryCacheKey(request, mappedData, fetcher, size)
//判断缓存策略,获取缓存
val value = if (request.memoryCachePolicy.readEnabled) memoryCacheService[memoryCacheKey] else null
// Ignore the cached bitmap if it is hardware-backed and the request disallows hardware bitmaps.
//获取缓存的bitmap
val cachedDrawable = value?.bitmap
?.takeIf { requestService.isConfigValidForHardware(request, it.safeConfig) }
?.toDrawable(context)
// Short circuit if the cached bitmap is valid.
//根据获取的缓存,判断缓存策略,如果有缓存,并且设置了缓存策略,直接返回缓存
if (cachedDrawable != null && isCachedValueValid(memoryCacheKey, value, request, size)) {
return SuccessResult(
drawable = value.bitmap.toDrawable(context),
request = request,
metadata = Metadata(
memoryCacheKey = memoryCacheKey,
isSampled = value.isSampled,
dataSource = DataSource.MEMORY_CACHE,
isPlaceholderMemoryCacheKeyPresent = chain.cached != null
)
)
}
// Fetch, decode, transform, and cache the image on a background dispatcher.
//没有缓存,协程切换io线程,开始请求
return withContext(request.dispatcher) {
// Mark the input data as ineligible for pooling (if necessary).
invalidateData(request.data)
// Decrement the value from the memory cache if it was not used.
if (value != null) referenceCounter.decrement(value.bitmap)
// Fetch and decode the image.
//执行请求
val (drawable, isSampled, dataSource) =
execute(mappedData, fetcher, request, chain.requestType, size, eventListener)
// Mark the drawable's bitmap as eligible for pooling.
validateDrawable(drawable)
// Cache the result in the memory cache.
//写入缓存
val isCached = writeToMemoryCache(request, memoryCacheKey, drawable, isSampled)
// Return the result.
//返回结果
SuccessResult(
drawable = drawable,
request = request,
metadata = Metadata(
memoryCacheKey = memoryCacheKey.takeIf { isCached },
isSampled = isSampled,
dataSource = dataSource,
isPlaceholderMemoryCacheKeyPresent = chain.cached != null
)
)
}
} catch (throwable: Throwable) {
if (throwable is CancellationException) {
throw throwable
} else {
return requestService.errorResult(chain.request, throwable)
}
}
}
根据上面分析,走到execute方法中获取图片
private suspend inline fun execute(
data: Any,
fetcher: Fetcher<Any>,
request: ImageRequest,
type: Int,
size: Size,
eventListener: EventListener
): DrawableResult {
val options = requestService.options(request, size, systemCallbacks.isOnline)
//请求开始
eventListener.fetchStart(request, fetcher, options)
//使用fetcher请求对应的数据
val fetchResult = fetcher.fetch(bitmapPool, data, size, options)
eventListener.fetchEnd(request, fetcher, options, fetchResult)
val baseResult = when (fetchResult) {
is SourceResult -> {
val decodeResult = try {
// Check if we're cancelled.
coroutineContext.ensureActive()
// Find the relevant decoder.
val isDiskOnlyPreload = type == REQUEST_TYPE_ENQUEUE &&
request.target == null &&
!request.memoryCachePolicy.writeEnabled
val decoder = if (isDiskOnlyPreload) {
// Skip decoding the result if we are preloading the data and writing to the memory cache is
// disabled. Instead, we exhaust the source and return an empty result.
EmptyDecoder
} else {
//解码请求的数据
request.decoder ?: registry.requireDecoder(request.data, fetchResult.source, fetchResult.mimeType)
}
// Decode the stream.
eventListener.decodeStart(request, decoder, options)
//解码
val decodeResult = decoder.decode(bitmapPool, fetchResult.source, size, options)
eventListener.decodeEnd(request, decoder, options, decodeResult)
decodeResult
} catch (throwable: Throwable) {
// Only close the stream automatically if there is an uncaught exception.
// This allows custom decoders to continue to read the source after returning a drawable.
fetchResult.source.closeQuietly()
throw throwable
}
// Combine the fetch and decode operations' results.
DrawableResult(
drawable = decodeResult.drawable,
isSampled = decodeResult.isSampled,
dataSource = fetchResult.dataSource
)
}
is DrawableResult -> fetchResult
}
// Check if we're cancelled.
coroutineContext.ensureActive()
// Apply any transformations and prepare to draw.
//转换得到的图片,如图片加圆角、渐变、高斯模糊
val finalResult = applyTransformations(baseResult, request, size, options, eventListener)
(finalResult.drawable as? BitmapDrawable)?.bitmap?.prepareToDraw()
return finalResult
}
调用fetcher.fetch方法获取数据,其中fetcher是上面通过 registry.requireFetcher(mappedData) 来获取,这个很像Glide的方式
@Suppress("UNCHECKED_CAST")
internal fun <T : Any> ComponentRegistry.requireFetcher(data: T): Fetcher<T> {
val result = fetchers.findIndices { (fetcher, type) ->
type.isAssignableFrom(data::class.java) && (fetcher as Fetcher<Any>).handles(data)
}
checkNotNull(result) { "Unable to fetch data. No fetcher supports: $data" }
return result.first as Fetcher<T>
}
上面的方法,就是循环fetchers,判断对应的class类型和handles方法获取对应的fetcher,其中fetchers的初始化在RealImageLoader中
private val registry = componentRegistry.newBuilder()
// Mappers
//添加转换器,上面讲string 转换成Uri,就是从这里获取
.add(StringMapper())
.add(FileUriMapper())
.add(ResourceUriMapper(context))
.add(ResourceIntMapper(context))
// Fetchers
//添加Fetchers
.add(HttpUriFetcher(callFactory))
.add(HttpUrlFetcher(callFactory))
.add(FileFetcher(addLastModifiedToFileCacheKey))
.add(AssetUriFetcher(context))
.add(ContentUriFetcher(context))
.add(ResourceUriFetcher(context, drawableDecoder))
.add(DrawableFetcher(drawableDecoder))
.add(BitmapFetcher())
// Decoders
//添加Decoders
.add(BitmapFactoryDecoder(context))
.build()
通过循环获取,所以第一次获取网络的图片是,使用的是HttpUriFetcher
调用HttpUriFetcher 的fetch 方法
override suspend fun fetch(
pool: BitmapPool,
data: T,
size: Size,
options: Options
): FetchResult {
val url = data.toHttpUrl()
val request = Request.Builder().url(url).headers(options.headers)
val networkRead = options.networkCachePolicy.readEnabled
val diskRead = options.diskCachePolicy.readEnabled
//判断缓存策略,通过okhttp设置网络和本地缓存策略
when {
!networkRead && diskRead -> {
request.cacheControl(CacheControl.FORCE_CACHE)
}
networkRead && !diskRead -> if (options.diskCachePolicy.writeEnabled) {
request.cacheControl(CacheControl.FORCE_NETWORK)
} else {
request.cacheControl(CACHE_CONTROL_FORCE_NETWORK_NO_CACHE)
}
!networkRead && !diskRead -> {
// This causes the request to fail with a 504 Unsatisfiable Request.
request.cacheControl(CACHE_CONTROL_NO_NETWORK_NO_CACHE)
}
}
//请求得到结果
val response = callFactory.newCall(request.build()).await()
if (!response.isSuccessful) {
response.body()?.close()
throw HttpException(response)
}
val body = checkNotNull(response.body()) { "Null response body!" }
return SourceResult(
source = body.source(),
mimeType = getMimeType(url, body),
dataSource = if (response.cacheResponse() != null) DataSource.DISK else DataSource.NETWORK
)
}
这里设置了网络、本地缓存,都是基于okhttp设置的。得到了HTTP请求的数据,通过decode进行解码,其中decode为BitmapFactoryDecoder,decode方法主要是根据Source计算bitmap大小,获取对应的bitmap,得到bitmap后,在走一遍transformations,对bitmap设置不同效果,得到最终的效果后,回调 onSuccess 中,也就是ImageViewTarget 的onSuccess方法中
override fun onSuccess(result: Drawable) = setDrawable(result)
protected open fun setDrawable(drawable: Drawable?) {
(view.drawable as? Animatable)?.stop()
view.setImageDrawable(drawable)
updateAnimation()
}
最后设置对应的图片。