coil icon indicating copy to clipboard operation
coil copied to clipboard

Why fetcher class mark as internal

Open xiaopao2014 opened this issue 2 years ago • 1 comments

Some times i have Image which like: 1.try first url,if success, use it 2.try second url, if success,use it 3.if all fail ,try other way

as i think, i should implement a Fetcher by myself , which may use HttpUriFetcher object. But HttpUriFetcher is internal class , i could't override it or create instance

It should be able to extend HttpUriFetcher

xiaopao2014 avatar Aug 11 '22 02:08 xiaopao2014

As i check history, there is some old issue about this. I think, if we use HttpUriFetcher just according Fetcher interface, you can still change the implement code as you wish


class SerialFetcher(
    private val data: TestItem,
    private val options: Options,
    callFactory: Lazy<Call.Factory>,
    diskCache: Lazy<DiskCache?>,
    respectCacheHeaders: Boolean,
    private val imageLoader: ImageLoader
) : Fetcher {
    val httpUriFetcher = HttpUriFetcher.Factory(callFactory, diskCache, respectCacheHeaders)

    override suspend fun fetch(): FetchResult? {
        var urlFetcher = httpUriFetcher.create(Uri.parse(data.url), options, imageLoader)
        var result = urlFetcher?.fetch()
        if (result != null) {
            return result
        }
        urlFetcher = httpUriFetcher.create(Uri.parse(data.url2), options, imageLoader)
        result = urlFetcher?.fetch()
        if (result != null) {
            return result
        }
        //get file by serial
        return null
    }

    class Factory(
        private val callFactory: Lazy<Call.Factory>,
        private val diskCache: Lazy<DiskCache?>,
        private val respectCacheHeaders: Boolean
    ) : Fetcher.Factory<TestItem> {
        override fun create(data: TestItem, options: Options, imageLoader: ImageLoader): Fetcher? {
            return SerialFetcher(
                data,
                options,
                callFactory,
                diskCache,
                respectCacheHeaders,
                imageLoader
            )
        }
    }
}

xiaopao2014 avatar Aug 11 '22 05:08 xiaopao2014

You should use delegation for this use case. HttpUriFetcher is internal so the arguments it accepts can easily be changed in the future to add new functionality. Using delegation instead keeps the components decoupled. Inside your fetch method you can do:

val mappedData = imageLoader.components.map(url, options)
val (fetcher) = checkNotNull(imageLoader.newFetcher(mappedData, options, imageLoader)) { "no fetcher to handle data: $data" }
fetcher.fetch() // will attempt to fetch the url

I'll add a section to the docs as well to better document this.

colinrtwhite avatar Aug 15 '22 05:08 colinrtwhite

@colinrtwhite Is the solution documented now? I think https://coil-kt.github.io/coil/image_pipeline/ should mention it. Btw, the correct code should be imageLoader.components.newFetcher(mappedData, options, imageLoader)

darktiny avatar Jul 20 '23 14:07 darktiny