coil-kt / coil Goto Github PK
View Code? Open in Web Editor NEWImage loading for Android and Compose Multiplatform.
Home Page: https://coil-kt.github.io/coil/
License: Apache License 2.0
Image loading for Android and Compose Multiplatform.
Home Page: https://coil-kt.github.io/coil/
License: Apache License 2.0
Describe the bug
I tried to set up image sampling the way it is described in :
https://coil-kt.github.io/coil/getting_started/#image-sampling
but I don't see any low-res image loaded with a crossfade effect to the high-res image.
To Reproduce
imageView.load(image) {
crossfade(true)
}
I am loading images in a RecyclerView.Adapter
.
Expected behavior
A crossfade effect from low to the high res image.
Logs/Screenshots
Library version
e.g. 0.6.0
Describe the bug
See strict mode warning below.
To Reproduce
Use Image.load() from inside a RecyclerView.Adapter. I didn't see it happening when it's used from inside a Fragment.
Expected behavior
Dispatchers.IO should be used. It also wouldn't hurt to be able to pass a custom lifecycle (actually a different issue) as well.
Logs/Screenshots
2019-08-19 16:00:08.236 17277-17277/ D/StrictMode: StrictMode policy violation; ~duration=326 ms: android.os.strictmode.DiskReadViolation
at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1504)
at java.io.UnixFileSystem.checkAccess(UnixFileSystem.java:251)
at java.io.File.exists(File.java:1152)
at java.io.File.mkdirs(File.java:1714)
at coil.util.Utils.getDefaultCacheDirectory(Utils.kt:33)
at coil.ImageLoaderBuilder.buildDefaultOkHttpClient(ImageLoaderBuilder.kt:189)
at coil.ImageLoaderBuilder.build(ImageLoaderBuilder.kt:182)
at coil.Coil.buildDefaultImageLoader(Coil.kt:57)
at coil.Coil.loader(Coil.kt:20)
...
Library version
0.6.1
Describe the bug
Coil causes a memory leak when finish()
is called on an Activity that has an ongoing request.
To Reproduce
Download & run the attached project:
CoilMemoryLeak.zip
ActivityA
tries to load an "image" from a URL that takes 60 seconds to respond. If you click the "Go to Activity B" button during that time, then LeakCanary should detect retained objects (check the notification). This does not happen if the request has finished before going to ActivityB
.
Expected behavior
Any references to the Activity should always be cleared when it is destroyed.
Logs/Screenshots
2019-08-12 14:51:11.619 8859-9256/com.example.coilmemoryleak D/LeakCanary: HeapAnalysisSuccess(heapDumpFile=/data/user/0/com.example.coilmemoryleak/files/leakcanary/2019-08-12_14-50-53_530.hprof, createdAtTimeMillis=1565610671616, analysisDurationMillis=14783, applicationLeaks=[ApplicationLeak(className=com.example.coilmemoryleak.ActivityA, leakTrace=
┬
├─ android.os.HandlerThread
│ Leaking: NO (PathClassLoader↓ is not leaking)
│ Thread name: 'LeakCanary-Heap-Dump'
│ GC Root: Thread object
│ ↓ thread HandlerThread.contextClassLoader
├─ dalvik.system.PathClassLoader
│ Leaking: NO (Object[]↓ is not leaking and A ClassLoader is never leaking)
│ ↓ PathClassLoader.runtimeInternalObjects
├─ java.lang.Object[]
│ Leaking: NO (Coil↓ is not leaking)
│ ↓ array Object[].[870]
├─ coil.Coil
│ Leaking: NO (a class is never leaking)
│ ↓ static Coil.imageLoader
│ ~~~~~~~~~~~
├─ coil.RealImageLoader
│ Leaking: UNKNOWN
│ ↓ RealImageLoader.loaderScope
│ ~~~~~~~~~~~
├─ kotlinx.coroutines.internal.ContextScope
│ Leaking: UNKNOWN
│ ↓ ContextScope.coroutineContext
│ ~~~~~~~~~~~~~~~~
├─ kotlin.coroutines.CombinedContext
│ Leaking: UNKNOWN
│ ↓ CombinedContext.left
│ ~~~~
├─ kotlinx.coroutines.SupervisorJobImpl
│ Leaking: UNKNOWN
│ ↓ SupervisorJobImpl._state
│ ~~~~~~
├─ kotlinx.coroutines.NodeList
│ Leaking: UNKNOWN
│ ↓ NodeList._next
│ ~~~~~
├─ kotlinx.coroutines.ChildHandleNode
│ Leaking: UNKNOWN
│ ↓ ChildHandleNode.childJob
│ ~~~~~~~~
├─ kotlinx.coroutines.StandaloneCoroutine
│ Leaking: UNKNOWN
│ ↓ StandaloneCoroutine._state
│ ~~~~~~
├─ kotlinx.coroutines.ChildHandleNode
│ Leaking: UNKNOWN
│ ↓ ChildHandleNode.childJob
│ ~~~~~~~~
├─ kotlinx.coroutines.UndispatchedCoroutine
│ Leaking: UNKNOWN
│ ↓ UndispatchedCoroutine.uCont
│ ~~~~~
├─ coil.RealImageLoader$load$job$1
│ Leaking: UNKNOWN
│ Anonymous subclass of kotlin.coroutines.jvm.internal.SuspendLambda
│ ↓ RealImageLoader$load$job$1.$request
│ ~~~~~~~~
├─ coil.request.LoadRequest
│ Leaking: UNKNOWN
│ ↓ LoadRequest.context
│ ~~~~~~~
╰→ com.example.coilmemoryleak.ActivityA
Leaking: YES (Activity#mDestroyed is true and ObjectWatcher was watching this)
key = 0893b148-6f03-4932-ad48-e07e204abb86
watchDurationMillis = 336257
retainedDurationMillis = 331257
, retainedHeapByteSize=69591)], libraryLeaks=[])
Library version
0.6.0
It would be cool if passing null url would use placeholder drawable or error drawable if set. Right now it defeats the purpose of fluent api when you have to do something like:
if (imageUrl != null) { it.load(imageUrl) { placeholder(placeholderRes) } } else { it.setImageResource(placeholderRes) }
If in build.gradle i have
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}
I'll get this error if i'll try to do imageView.load("url")
Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option
At the documentation it says minSdkVersion = 14 , but When I run the app, it says that it requires Android N , minSdkVersion = 24 to run
I changed the minSdkVersion in my gradle to 24 and the app is running
Describe the bug
Since Coil uses JVM target 1.8, this must be used in the application project as well. However, setting that target JVM can cause the Kotlin compiler to generate byte code that incompatible with Android SDK versions less than 24. See https://youtrack.jetbrains.com/issue/KT-19968.
To Reproduce
Use code similar to the code in the linked Kotlin issue. Try to run on a device with SDK version < 24.
Expected behavior
No hashCode related errors.
Logs/Screenshots
java.lang.NoSuchMethodError: No static method hashCode(J)I in class Ljava/lang/Long; or its super classes (declaration of 'java.lang.Long' appears in /system/framework/core-libart.jar)
Library version
0.6.0
holder.imageViewCover.scaleType = ImageView.ScaleType.CENTER_CROP
holder.imageViewCover.load(producList[position].cover_image) {
transformations(RoundedCornersTransformation(32f))
}
but the image is not rounded conner
Latest version 0.7.0 while creating software bitmaps from SVG assets causing an OOM exception when loading SVGs in a recyclerview. Was able to reproduce this 100% of the time on memory constrained Nexus 5x device.
To reproduce, create a basic recyclerview that loads a unique SVG graphic from web, and start scrollin'.
java.lang.OutOfMemoryError: Failed to allocate a 16000012 byte allocation with 8363936 free bytes and 7MB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:831)
at android.graphics.Bitmap.createBitmap(Bitmap.java:808)
at android.graphics.Bitmap.createBitmap(Bitmap.java:775)
at coil.bitmappool.RealBitmapPool.get(RealBitmapPool.kt:77)
at coil.drawable.SvgDrawable.draw(SvgDrawable.kt:50)
at android.widget.ImageView.onDraw(ImageView.java:1246)
at android.view.View.draw(View.java:16184)
at android.view.View.updateDisplayListIfDirty(View.java:15180)
at android.view.View.draw(View.java:15954)
at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:1765)
at android.view.View.draw(View.java:16187)
at android.view.View.updateDisplayListIfDirty(View.java:15180)
at android.view.View.draw(View.java:15954)
at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
at androidx.recyclerview.widget.RecyclerView.drawChild(RecyclerView.java:5018)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
at android.view.View.draw(View.java:16187)
at androidx.recyclerview.widget.RecyclerView.draw(RecyclerView.java:4417)
at android.view.View.updateDisplayListIfDirty(View.java:15180)
at android.view.View.draw(View.java:15954)
at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
at android.view.View.draw(View.java:16187)
at android.view.View.updateDisplayListIfDirty(View.java:15180)
at android.view.View.draw(View.java:15954)
at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
at androidx.coordinatorlayout.widget.CoordinatorLayout.drawChild(CoordinatorLayout.java:1256)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
at android.view.View.updateDisplayListIfDirty(View.java:15175)
at android.view.View.draw(View.java:15954)
at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
at androidx.fragment.app.FragmentContainerView.drawChild(FragmentContainerView.java:144)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
at androidx.fragment.app.FragmentContainerView.dispatchDraw(FragmentContainerView.java:133)
at android.view.View.updateDisplayListIfDirty(View.java:15175)
at android.view.View.draw(View.java:15954)
at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:1765)
at android.view.View.updateDisplayListIfDirty(View.java:15175)
at android.view.View.draw(View.java:15954)
at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
at android.view.View.updateDisplayListIfDirty(View.java:15175)
at android.view.View.draw(View.java:15954)
at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
at android.view.View.updateDisplayListIfDirty(View.java:15175)
at android.view.View.draw(View.java:15954)
at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
at android.view.View.updateDisplayListIfDirty(View.java:15175)
at android.view.View.draw(View.java:15954)
at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
at android.view.View.updateDisplayListIfDirty(View.java:15175)
at android.view.View.draw(View.java:15954)
at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
at android.view.View.draw(View.java:16187)
at com.android.internal.policy.PhoneWindow$DecorView.draw(PhoneWindow.jav
Describe the bug
When dimensions of ImageView are computed in ConstraintLayout with a constraint width percent, the size of the image is incorrect.
To Reproduce
Project is available. Search for ImageView with cover id.
https://github.com/damienLh/entract-cinema-android/blob/coil/app/src/main/res/layout/fragment_details.xml
https://github.com/damienLh/entract-cinema-android/blob/coil/app/src/main/kotlin/com/cinema/entract/app/ui/details/DetailsFragment.kt
Expected behavior
ImageView dimensions set to correct width percent constraint. In this example third of the screen width.
Logs/Screenshots
Current behaviour:
Library version
0.7.0
Describe the bug
When an app makes use of Robolectric and tests fragments or activities which in turn use Coil to load images, the default image loader needs to be initialized manually (via CoilContentProvider). The canonical way to do this with Robolectric would be to put this in a @before method in a JUnit4 based unit test class or a custom Application instance:
Robolectric.setupContentProvider(CoilContentProvider::class.java)
This doesn't work though as CoilContentProvider is internal. So the most viable option is
Coil.setDefaultImageLoader(ImageLoader(ApplicationProvider.getApplicationContext()))
To Reproduce
Invoke a unit test for a fragment or activity using coil (e.g. with launchFragmentInContainer, the new way to test fragments).
Expected behavior
The usage of setDefaultImageLoader is a little hidden in the existing documentation. Ideally, a dedicated Testing page with a paragraph on Robolectric would be good (I'm willing to start writing it) and / or CoilContentProvider is marked as @VisibleForTesting.
Logs/Screenshots
java.lang.Exception: Main looper has queued unexecuted runnables. This might be the cause of the test failure. You might need a shadowOf(getMainLooper()).idle() call.
at org.robolectric.android.internal.AndroidTestEnvironment.checkStateAfterTestFailure(AndroidTestEnvironment.java:470)
at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:548)
at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:252)
at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property context has not been initialized
at coil.util.CoilContentProvider$Companion.getContext$coil_default_release(CoilContentProvider.kt:17)
at coil.Coil.buildDefaultImageLoader(Coil.kt:48)
at coil.Coil.loader(Coil.kt:20)
Library version
0.7.0
Describe Bug
To ManyRequest Exception on scroll recyclerview
Reproduce
Create recyclerview with the adapter using image url and scrolling from top list to bottom list with repeatedly
Error Message
E/UncaughtException: android.net.ConnectivityManager$TooManyRequestsException
at android.net.ConnectivityManager.convertServiceException(ConnectivityManager.java:2888)
at android.net.ConnectivityManager.sendRequestForNetwork(ConnectivityManager.java:3061)
at android.net.ConnectivityManager.registerNetworkCallback(ConnectivityManager.java:3366)
at android.net.ConnectivityManager.registerNetworkCallback(ConnectivityManager.java:3348)
at coil.network.NetworkObserverStrategyApi21.start(NetworkObserverStrategy.kt:102)
at coil.network.NetworkObserver.(NetworkObserver.kt:27)
at coil.RealImageLoader.(RealImageLoader.kt:94)
at coil.ImageLoaderBuilder.build(ImageLoaderBuilder.kt:177)
and I use this code for load image url
val cacheDirectory = context.cacheDir
val cacheSize:Long = 200
val cache = Cache(cacheDirectory, cacheSize)
val client = OkHttpClient.Builder().cache(cache).build()
val imageLoader = ImageLoader(context) {
availableMemoryPercentage(0.25)
bitmapPoolPercentage(0.25)
crossfade(true)
placeholder(context.getDrawable(R.drawable.ic_picture_placeholder))
allowRgb565(true)
okHttpClient(client)
}
imageView?.load(uri, imageLoader) {
memoryCachePolicy(CachePolicy.DISABLED)
diskCachePolicy(CachePolicy.DISABLED)
}
is it possible to use a signature like Glide did it before, and they reload image from cache first if the image already loaded before?
Is your feature request related to a problem? Please describe.
Suppose an ImageView
showing the user's avatar. The user's avatar is loaded with a placeholder and has the CircleCropTransformation
transformation applied to it. The placeholder will not be round which may cause the app to not look right on places where the avatar is expected to always be a circle.
Describe the solution you'd like
It should be possible to apply tranformations to the placeholder/error drawable as well. This could either be something like transformationsPlaceholder(...)
or enablePlaceholderTransformations(true)
.
Another option would be to provide an overload on placeholder
that accepts a RequestDisposable
as an argument (similar to how Glide does it). This would also solve #27.
Describe the bug
When set the availableMemoryPercentage
to 0.0
it crashes the app in the LruCache
To Reproduce
Coil.setDefaultImageLoader {
ImageLoaderBuilder(application)
.availableMemoryPercentage(0.0)
.build()
}
Expected behavior
Setting availableMemoryCache to 0 disables the cache not crashes.
Logs/Screenshots
java.lang.IllegalArgumentException: maxSize <= 0
at androidx.collection.LruCache.<init>(LruCache.java:53)
at coil.memory.MemoryCache$cache$1.<init>(MemoryCache.kt:24)
at coil.memory.MemoryCache.<init>(MemoryCache.kt:24)
at coil.RealImageLoader.<init>(RealImageLoader.kt:93)
at coil.ImageLoaderBuilder.build(ImageLoaderBuilder.kt:177)
Library version
0.6.1
Describe the bug
When images are loaded with URLs in a RecyclerView, the RecyclerView is still blank. I believe this could be because after the image is retrieved, there is no call to remeasure/invalidate/notify the view.
To Reproduce
Create a Single page application with a RecyclerView and a ViewHolder containing an ImageView.
Load up an image into the ImageView
Code snippet below:
class Adapter(private val urlList: List<String>) : RecyclerView.Adapter<VH>() {
override fun getItemCount(): Int = urlList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH = VH(ImageView(parent.context))
override fun onBindViewHolder(holder: VH, position: Int) {
holder.imageView.load(urlList[position])
}
}
class VH(val imageView: ImageView) : RecyclerView.ViewHolder(imageView)
Expected behavior
I expect the Image to load up like in Glide and Picasso.
The only way i can get it to show up in a RecyclerView at the moment is if I set the height of the view to a non-zero value.
Logs/Screenshots
If applicable, add logs or screenshots to help explain your problem.
Library version
0.6.0
Describe the bug
Loading an image with crossfade and a placeholder enabled can result in a stretched image if the ImageView uses wrap_content
and the placeholder has a different aspect ratio than the image being loaded.
If the app goes to the background and then to the foreground again, the image appears correctly.
(the placeholder has to be larger than the ImageView for this to occur)
To Reproduce
Sample project: CoilPlaceholderAR.zip
Expected behavior
The loaded image should not appear stretched.
Library version
0.6.1 (manually compiled)
Latest version 0.7.0 crash when attempting to get SVG asset via Coil.get() and using Drawable .toBitmap() to convert it to a bitmap.
Usage:
Coil.get(iconUrl)
.toBitmap()
Stacktrace:
java.lang.IllegalArgumentException: width and height must be > 0
at android.graphics.Bitmap.createBitmap(Bitmap.java:829)
at android.graphics.Bitmap.createBitmap(Bitmap.java:808)
at android.graphics.Bitmap.createBitmap(Bitmap.java:775)
at androidx.core.graphics.drawable.DrawableKt.toBitmap(Drawable.kt:60)
at androidx.core.graphics.drawable.DrawableKt.toBitmap$default(Drawable.kt:45)
...
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740)
please add this
val drawableGif = Coil.get("https://www.example.com/mygif.gif")
like to get an image:
To get an image imperatively, use the get suspend function:
val drawable = Coil.get("https://www.example.com/image.jpg")
Is your feature request related to a problem? Please describe.
I would like to know, how can I optimize Coil for proper work with RecyclerView. I am loading the whole device's gallery in it using Coil and it properly loads all images separately, but if I would scroll list there are animations drops. Maybe there is some kind of optimization for such situations?
Describe the bug
A clear and concise description of what the bug is.
When images are loaded with URLs in a RecyclerView, the RecyclerView is still blank. I believe this could be because after the image is retrieved, there is no call to remeasure/invalidate/notify the view.
To Reproduce
How can we reproduce this?
class Adapter(private val list: List<String>) : RecyclerView.Adapter<VH>() {
override fun getItemCount(): Int = list.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH = VH(ImageView(parent.context))
override fun onBindViewHolder(holder: VH, position: Int) {
holder.imageView.load(list[position])
}
}
class VH(val imageView: ImageView) : RecyclerView.ViewHolder(imageView)
Expected behavior
A clear and concise description of what you expected to happen.
I expect the Image to load up like in Glide and Picasso.
The only way i can get it to show up in a RecyclerView at the moment is if I set the height of the view to a non-zero value.
Logs/Screenshots
If applicable, add logs or screenshots to help explain your problem.
Library version
0.6.0
Is your feature request related to a problem? Please describe.
ImageView.load("file:///data/user/0/foo/cache/1.jpg")
fails with
java.lang.IllegalArgumentException: Expected URL scheme 'http' or 'https' but was 'file'
at okhttp3.HttpUrl$Builder.parse(HttpUrl.java:1328)
because it is directly handed down to OkHttp3.
Describe the solution you'd like
A check if the Uri starts with *file:// could map to load(file: File) instead.
Describe the bug
I have recently switched from Glide to Coil as image loading library, but after having implemented Coil just some images are loaded, the ones that are loaded by URL, while vector drawables are not displayed at all, even though I'm trying to strictly follow the documentation
To Reproduce
Create a vector drawable, place it under /res/drawables, then
val icon = layout.find<ImageView>(R.id.status_icon)
icon.load(R.drawable.status_ok)
Expected behavior
The icon should be displayed correctly
Coil Version 0.6.1
In our projects with minimal API 21,
we use fresco library to load an amount of animated-webp
(from local file in assets and also from url)
I can see there's a GifDecoder for gif decoding/loading for all API level.
Would Coil support a decoder like WebPDecoder prior to Android P?
Is your feature request related to a problem? Please describe.
Implementing a custom fetcher seems to also require the implementation of disk cache.
Describe the solution you'd like
An interface to provide a bitmap and have it cached on disk, preventing unnecessary fetches.
Note
I apologize if I'm missing a simple solution.
Setup a benchmark (memory, time, library size) with Glide, Fresco, Picasso for common set of scenarios
Why?
Describe the bug
When displaying GIF images, previous frames are not deleted
To Reproduce
io.coil-kt:coil-gif
to dependenciesReproduces on device LG V30+ (Android 8.0 Stock)
Expected behavior
Previous GIF images will disappear after changing the frame
Logs/Screenshots
Usage:
Image container:
Library version
Version 0.6.0
I attempted to migrate from Glide to Coil in my app. After switching to Coil, the app crashed in runtime as soon as an image was downloaded when it was being set to a androidx.appcompat.widget.AppCompatImageView
descendant.
May be worth to note, that I'm using this ui library: https://github.com/stfalcon-studio/ChatKit
Could you help me understand what the issue is and if there are any possible workarounds?
Here's the stacktrace:
java.lang.IllegalArgumentException: Software rendering doesn't support hardware bitmaps at android.graphics.BaseCanvas.onHwBitmapInSwMode(BaseCanvas.java:550) at android.graphics.BaseCanvas.throwIfHwBitmapInSwMode(BaseCanvas.java:557) at android.graphics.BaseCanvas.throwIfCannotDraw(BaseCanvas.java:69) at android.graphics.BaseCanvas.drawBitmap(BaseCanvas.java:127) at android.graphics.Canvas.drawBitmap(Canvas.java:1504) at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:545) at android.widget.ImageView.onDraw(ImageView.java:1360) at com.stfalcon.chatkit.utils.ShapeImageView.onDraw(ShapeImageView.java:70) at android.view.View.draw(View.java:20207) at android.view.View.buildDrawingCacheImpl(View.java:19478) at android.view.View.buildDrawingCache(View.java:19338) at android.view.View.draw(View.java:19927) at android.view.ViewGroup.drawChild(ViewGroup.java:4333) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4112) at android.view.View.updateDisplayListIfDirty(View.java:19073) at android.view.View.draw(View.java:19935) at android.view.ViewGroup.drawChild(ViewGroup.java:4333) at androidx.recyclerview.widget.RecyclerView.drawChild(RecyclerView.java:5011) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4112) at android.view.View.draw(View.java:20210) at androidx.recyclerview.widget.RecyclerView.draw(RecyclerView.java:4410) at android.view.View.updateDisplayListIfDirty(View.java:19082) at android.view.View.draw(View.java:19935) at android.view.ViewGroup.drawChild(ViewGroup.java:4333) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4112) at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:2023) at android.view.View.draw(View.java:20210) at android.view.View.updateDisplayListIfDirty(View.java:19082) at android.view.View.draw(View.java:19935) at android.view.ViewGroup.drawChild(ViewGroup.java:4333) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4112) at android.view.View.draw(View.java:20210) at android.view.View.updateDisplayListIfDirty(View.java:19082) at android.view.View.draw(View.java:19935) at android.view.ViewGroup.drawChild(ViewGroup.java:4333) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4112) at android.view.View.updateDisplayListIfDirty(View.java:19073) at android.view.View.draw(View.java:19935) at android.view.ViewGroup.drawChild(ViewGroup.java:4333) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4112) at android.view.View.updateDisplayListIfDirty(View.java:19073) at android.view.View.draw(View.java:19935) at android.view.ViewGroup.drawChild(ViewGroup.java:4333) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4112) at android.view.View.updateDisplayListIfDirty(View.java:19073) at android.view.View.draw(View.java:19935) at android.view.ViewGroup.drawChild(ViewGroup.java:4333) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4112) at android.view.View.updateDisplayListIfDirty(View.java:19073) at android.view.View.draw(View.java:19935) at android.view.ViewGroup.drawChild(ViewGroup.java:4333) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4112) at android.view.View.draw(View.java:20210) at com.android.internal.policy.DecorView.draw(DecorView.java:780) at android.view.View.updateDisplayListIfDirty(View.java:19082) at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:686) at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:692) at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:801) at android.view.ViewRootImpl.draw(ViewRootImpl.java:3311) at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:3115) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2484) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1460) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7183) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:949) at android.view.Choreographer.doCallbacks(Choreographer.java:761) at android.view.Choreographer.doFrame(Choreographer.java:696) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6669) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Describe the bug
Crash on Android 9.0 when loading GIF-image
To Reproduce
io.coil-kt:coil-gif
to dependenciesExpected behavior
GIF picture will load and move
Logs/Screenshots
A/libc: Fatal signal 6 (SIGABRT), code -6 (SI_TKILL) in tid 8197 (AnimatedImageTh), pid 8010 (app.package.name)
Usage:
Image container:
Tested on devices:
Library version
version 0.6.0
Describe the bug
Assume the following ImageView:
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:adjustViewBounds="true"
android:scaleType="fitCenter" />
If you try to load an image to it, Coil will not calculate the correct width (based on the ImageView's fixed height and the aspect ratio of the image being loaded), and the ImageView will end up with a 0 width.
Using size()
solves this issue, but it is not ideal because it is not always possible to know beforehand the dimensions of the image being loaded.
To Reproduce
Load an image to an ImageView which has one fixed dimension, and one wrap_content
dimension.
Sample project: CoilWrapContent.zip
Expected behavior
Coil should automatically calculate the dimension set to wrap_content
based on the fixed dimension & the dimensions of the image being loaded.
For example: If I load a 400x200 (2:1 aspect ratio) image to an ImageView with android:layout_width="wrap_content"
and android:layout_height="100dp"
, then Coil should automatically set the width to 200dp (perhaps this shouldn't apply to all scaleTypes).
Logs/Screenshots
Layout Inspector screenshot showing the ImageView having its width set to 0:
Library version
0.6.0
Is your feature request related to a problem? Please describe.
load(file)
method cannot load the video cover.Describe the solution you'd like
Glide
is very compatible with image and video files. Loading video sequence frames is also very convenient,such as:
Glide.with(frameView).load(videoPath).apply(RequestOptions.frameOf(video.time * 1000).centerCrop()).into(frameView)
Describe the bug
I am using io.coil-kt:coil-base
because I want to take advantage of DI.
However, I am not sure how to use ImageVIew
. There seems to be some IDE wired behavior where get
methods are visible in code completion but missing in the actual code.
To Reproduce
How can we reproduce this?
import android.os.Bundle
import androidx.navigation.findNavController
import androidx.navigation.ui.setupWithNavController
import coil.ImageLoader
import com.igorwojda.showcase.R
import com.igorwojda.showcase.base.presentation.activity.BaseActivity
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : BaseActivity() {
override val layoutResId = R.layout.activity_main
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val imageLoader = ImageLoader(this)
CoroutineScope(Dispatchers.Main).launch {
imageLoader.get("url")
}
}
}
Code completion seems to show all posibilitie overloads (inclusing ImageView
extensions)
Expected behavior
Just load an image using the get method
imageLoader.get("url")
(ideally, ImageView
instance will be injected - this is a simplified example)
Library version
e.g. 0.6.0
First up, congrats on shipping!
A feature request for consideration. Sometimes an app will show a list of small image thumbnails, which are clickable to open the image full screen. The thumbnails are physically small (in dimension and file size) so the list of thumbnails loads quickly. The full images (loaded from a different URL to the thumbnail) are much bigger, so might take a few seconds to load from the network.
Currently, Coil supports specifying a placeholder Drawable
using the placeholder
method. It would be good if that was extended to allow passing in the URL of the thumbnail, which presumably would still be in the memory cache because it was being displayed on the previous screen.
The desired effect would look like the image sampling mentioned on the docs website. So the low-res thumbnail would be shown until the full-res image has loaded. The API difference being the first low-res image has come from a different URL, rather than the same one.
I've used "URL" above to keep the wording simple, but I mean all the different "sources" in general that are parameters to the ImageLoader.load
methods (String
, Uri
, HttpUrl
, etc), or the loadAny
method that uses a Mapper.
memoryCachePolicy(CachePolicy.DISABLED)
after loading the same picture will cause flicker, glide has dontAnimate()
can solve, the coil?
Describe the bug
When images have rotation information embedded within their Exif information, Coil should use that to automatically rotate the image correctly.
This is something that other image libraries (Glide, Picasso) do already. Using the AndroidX ExifInterface library allows you to extract the orientation information from any Uri
/ InputStream
.
To Reproduce
You can use this sample image.
Expected behavior
The image should be rotated correctly.
Logs/Screenshots
n/a
Library version
0.6.1
Currently using Glide to load SVG images and the implementation is quite clunky in order to do so. See: https://stackoverflow.com/questions/35507893/does-glide-have-a-method-for-loading-both-png-and-svg
As a fresh new library hot off the presses, I'd like to see Coil gracefully (and optimally) handle these file formats without a ton of boilerplate.
EDIT: WebP is already supported, so this enhancement request is more about formats that require an external library for decoding (and a Decoder).
Thanks!
Is your feature request related to a problem? Please describe.
There's a very specific type of Uri
on Android in the form of file:///android_asset/your_asset.jpg
which, despite its file://
prefix, cannot be opened with ContentResolver.openInputStream()
but instead must be opened using AssetManager
.
This is true for all Uris in the form of ContentResolver.SCHEME_FILE + ":///android_asset/"
.
Describe the solution you'd like
I'd like to be able to use:
imageView.load("file:///android_asset/starrynight.jpg")
And have it automatically use AssetManager
. I'd also be fine with using the load(Uri)
version, although that would be a difference from Picasso and Glide (see examples below).
Additional context
Assets are already supported by Picasso:
Picasso.get().load("file:///android_asset/starrynight.png").into(imageView)
and Glide
Glide.with(this).load("file:///android_asset/starrynight.jpg").into(imageView)
Trying to implement Coil on my existing application where Glide already using.
Need to achieve this...
val bitmapTarget = object : CustomTarget<Bitmap>(DeviceUtils.dpToPx(282), DeviceUtils.dpToPx(159)) {
override fun onLoadCleared(placeholder: Drawable?) {
}
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
if (activity != null && isAdded) {
row.setImageBitmap(mContext, resource)
arrayAdapter!!.notifyArrayItemRangeChanged(0, arrayAdapter!!.size())
}
}
}
GlideApp.with(mContext)
.asBitmap()
.load(thumbImage)
.into(bitmapTarget)
Sometimes in some combination transformations, it is possibly important
Is your feature request related to a problem? Please describe.
Currently the RoundedCornersTransformation only allows the setting of the radius for all corners, RoundedCornersTransformation(radius:Float)
. It would be nice to have the flexibility to specify the corners that I would to have the radius applied only.
Describe the solution you'd like
Example would be for the api to be like RoundedCornersTransformation(radius:Float, RoundedCornersTransformation.TOP_LEFT or RoundedCornersTransformation.TOP_RIGHT)
using an IntDef
to specify corners to apply the radius.
The IntDef
list could be like
RoundedCornersTransformation.TOP_RIGHT
RoundedCornersTransformation.TOP_LEFT
RoundedCornersTransformation.BOTTOM_LEFT
RoundedCornersTransformation.BOTTOM_RIGHT
RoundedCornersTransformation.ALL
Is your feature request related to a problem? Please describe.
Thanks for this awesome library! I am trying it out in a project currently.
However, I am sending access tokens when loading the images.
Glide.with(context)
.load(GlideUrl(imageUrl, LazyHeaders.Builder().addHeader(AUTHORIZATION, accessToken).build()))
.into(imageView)
I looked around in the docs but couldn't find anything related to sending tokens in request headers.
Describe the solution you'd like
It would be great to have something like this:
imageView.load(imageUrl).header(AUTHORIZATION, accessToken)
Describe the bug
imageView.load(uri)
doesn't load image from android.resource://
uri.
To Reproduce
detail.load(uri)
and un-comment detail.setImageURI(uri)
Expected behavior
Image loaded from uri
Logs/Screenshots
Current | Expected |
---|---|
![]() |
![]() |
Library version
0.6.1
tested on Android 10
Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is.
I'm not quite understanding why the implementation chose to go with a custom RequestDisposable
over job or a pure suspending alternative. Normally, I delegate some network tasks in my RecyclerViews to my ViewHolders like so
abstract class CoroutineViewHolder(
itemView: View,
scope: CoroutineScope
) : RecyclerView.ViewHolder(itemView), CoroutineScope by scope {
/**
* This establishes a lifecycle for recycling of views for
* coroutine aware ViewHolders. Cancel the work that's being
* done if this view is recycled and no longer needed.
*/
@CallSuper
fun onRecycled() {
this.cancel("${this}.onRecycled called")
}
}
where onRecycled
is a method I call from a similar coroutine adapter I've made.
abstract class CoroutineAdapter<T : CoroutineViewHolder>(scope: CoroutineScope) : RecyclerView.Adapter<T>(), CoroutineScope by scope {
@CallSuper
override fun onViewRecycled(holder: T) {
super.onViewRecycled(holder)
holder.onRecycled()
}
}
needing to be bound to use a RequestDisposable
seems like reinventing the wheel to me. There's got to be something I'm missing for this design choice.
Describe the solution you'd like
If possible, a pure susending ImageView.load
function would be great.
Additional context
Add any other context or screenshots about the feature request here.
Describe the bug
The underlying network socket managed by OkHttp isn't tagged according to policy. Strict mode complains about it. While it's a longstanding OkHttp issue other libraries apply a fixed tag.
To Reproduce
Enable strict mode in an app's Application class during onCreate():
if (BuildConfig.DEBUG) {
StrictMode.enableDefaults()
}
Expected behavior
A clear and concise description of what you expected to happen.
Logs/Screenshots
2019-08-19 16:00:08.151 17277-17363/foo D/StrictMode: StrictMode policy violation: android.os.strictmode.UntaggedSocketViolation: Untagged socket detected; use TrafficStats.setThreadSocketTag() to track all network usage
at android.os.StrictMode.onUntaggedSocket(StrictMode.java:2023)
at com.android.server.NetworkManagementSocketTagger.tag(NetworkManagementSocketTagger.java:82)
...
at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:245)
...
Library version
0.6.1
Describe the bug
When I download a resource from URL and its size is smaller than the requested size in the GetRequestBuilder
, result is not upscaled. On the contrary, when I set a smaller size inside my GetRequestBuilder
, the resource is correctly downscaled.
To Reproduce
Download this image using Coil.get(url) { size(256, 256) }
Expected behavior
I would expect to have a resulting drawable of 256x256 instead of the 24x24 provided
Library version
0.6.1
Is your feature request related to a problem? Please describe.
Currently load(String)
must always be a valid URL, but we could support automatically switching between Uris
and HttpUrls
.
Describe the solution you'd like
This should load the file/asset Uri correctly:
imageView.load("file:///android_asset/starrynight.jpg")
Additional context
Glide and Picasso already handle this.
Previous discussion: #10
Is your feature request related to a problem? Please describe.
None of the various load methods allow to inspect error conditions, i.e. why an image load failed. At the moment it's next to a black box. Interestingly, there is no log output either.
Describe the solution you'd like
Probably the easiest solution is to let load() methods accept another lambda that is called in case of errors, i.e. onSuccess = (Exception) -> Unit = {}
Describe the bug
When loading a local jpg from the file-system, crossfade(true) causes a crash
To Reproduce
Happens when using coil with CircleImageView (didn't test plain ImageView).
Expected behavior
No crash.
Logs/Screenshots
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: java.lang.IllegalArgumentException: Software rendering doesn't support hardware bitmaps
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: at android.graphics.BaseCanvas.onHwBitmapInSwMode(BaseCanvas.java:550)
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: at android.graphics.BaseCanvas.throwIfHwBitmapInSwMode(BaseCanvas.java:557)
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: at android.graphics.BaseCanvas.throwIfCannotDraw(BaseCanvas.java:69)
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: at android.graphics.BaseCanvas.drawBitmap(BaseCanvas.java:127)
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: at android.graphics.Canvas.drawBitmap(Canvas.java:1504)
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:545)
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: at coil.drawable.CrossfadeDrawable.draw(CrossfadeDrawable.kt:41)
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: at de.hdodenhof.circleimageview.CircleImageView.getBitmapFromDrawable(CircleImageView.java:318)
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: at de.hdodenhof.circleimageview.CircleImageView.initializeBitmap(CircleImageView.java:330)
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: at de.hdodenhof.circleimageview.CircleImageView.setImageDrawable(CircleImageView.java:263)
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: at coil.target.ImageViewTarget.setDrawable(ImageViewTarget.kt:62)
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: at coil.target.ImageViewTarget.onSuccess(ImageViewTarget.kt:22)
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: at coil.memory.PoolableTargetDelegate.success(TargetDelegate.kt:192)
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: at coil.RealImageLoader$execute$2$deferred$1.invokeSuspend(RealImageLoader.kt:219)
2019-08-20 13:38:57.430 19165-19165/foo W/System.err: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
2019-08-20 13:38:57.431 19165-19165/foo W/System.err: at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:238)
2019-08-20 13:38:57.431 19165-19165/foo W/System.err: at android.os.Handler.handleCallback(Handler.java:873)
2019-08-20 13:38:57.431 19165-19165/foo W/System.err: at android.os.Handler.dispatchMessage(Handler.java:99)
2019-08-20 13:38:57.431 19165-19165/foo W/System.err: at android.os.Looper.loop(Looper.java:193)
2019-08-20 13:38:57.431 19165-19165/foo W/System.err: at android.app.ActivityThread.main(ActivityThread.java:6898)
2019-08-20 13:38:57.431 19165-19165/foo W/System.err: at java.lang.reflect.Method.invoke(Native Method)
2019-08-20 13:38:57.431 19165-19165/foo W/System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
2019-08-20 13:38:57.431 19165-19165/foo W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Library version
0.6.1
Is your feature request related to a problem? Please describe.
Pure-Kotlin Android projects don't have to care about Java8 compatibility and thus stick to Kotlin defaults (i.e. Java 1.6 bytecode compatibility).
> Failed to transform artifact 'lifecycle-common-java8.jar (androidx.lifecycle:lifecycle-common-java8:2.0.0)' to match attributes {artifactType=android-dex, dexing-enable-desugaring=false, dexing-is-debuggable=true, dexing-min-sdk=21, org.gradle.libraryelements=jar, org.gradle.usage=java-runtime}.
> Execution failed for DexingNoClasspathTransform: /home/saschpe/.gradle/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-common-java8/2.0.0/52cb9efc663d8bebc82f8979a7da30938bd05611/lifecycle-common-java8-2.0.0.jar.
Currently, one has to add quite a bit of boilerplate with Gradle Kotlin DSL:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
android {
compileOptions {
setSourceCompatibility(1.8)
setTargetCompatibility(1.8)
}
}
tasks.withType<KotlinCompile> { kotlinOptions.jvmTarget = "1.8" }
Describe the solution you'd like
Align with standard Kotlin and require only androidx.lifecycle:lifecycle-common:2.0.0
(and others) to increase compatibility.
Is your feature request related to a problem? Please describe.
Can you write something doc or example about usage of cache image with Coil ?
I really consider about cache image in Android ( Just refer to Glide cache at link : https://bumptech.github.io/glide/doc/caching.html#cache-keys )
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.