Coil relies on immediate dispatching to resolve from its memory cache synchronously. Dispatchers.Main.immediate is available almost everywhere except test and preview environments (e.g. Paparazzi, Roborazzi, AndroidX screenshot testing lib, and Android Studio previews). Technically the main thread can be overridden in these cases with Dispatchers.setMain, but we want to avoid requiring that. In those cases, fall back to Dispatchers.Unconfined. This works fine for most cases as Coil makes no assumptions about the context it is in and its components are thread safe except:
Cases where we need to touch a view or lifecycle. This is only an issue with ImageRequests launched off the main thread that have a ViewTarget.
AsyncImagePainter has no problem receiving the Image callback on any thread, but user code may be expecting the listeners to be invoked on the main thread (even though this is not part of Coil's API contract).
As Dispatchers.Unconfined will only end up being used in test/non prod code I feel OK about making this change since in those cases you should also set ImageLoader.Builder.coroutineContext(EmptyCoroutineContext) to load images synchronously. It may make sense to set ImageLoader.Builder.coroutineContext(EmptyCoroutineContext) automatically if Dispatchers.Main.immediate can't be resolved, but I'm unsure.
Coil relies on immediate dispatching to resolve from its memory cache synchronously.
Dispatchers.Main.immediate
is available almost everywhere except test and preview environments (e.g. Paparazzi, Roborazzi, AndroidX screenshot testing lib, and Android Studio previews). Technically the main thread can be overridden in these cases withDispatchers.setMain
, but we want to avoid requiring that. In those cases, fall back toDispatchers.Unconfined
. This works fine for most cases as Coil makes no assumptions about the context it is in and its components are thread safe except:ImageRequest
s launched off the main thread that have aViewTarget
.AsyncImagePainter
has no problem receiving theImage
callback on any thread, but user code may be expecting the listeners to be invoked on the main thread (even though this is not part of Coil's API contract).As
Dispatchers.Unconfined
will only end up being used in test/non prod code I feel OK about making this change since in those cases you should also setImageLoader.Builder.coroutineContext(EmptyCoroutineContext)
to load images synchronously. It may make sense to setImageLoader.Builder.coroutineContext(EmptyCoroutineContext)
automatically ifDispatchers.Main.immediate
can't be resolved, but I'm unsure.