Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions coil/src/androidMain/kotlin/coil3/SingletonImageLoader.android.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,16 @@ package coil3
internal actual fun PlatformContext.applicationImageLoaderFactory(): SingletonImageLoader.Factory? {
return applicationContext as? SingletonImageLoader.Factory
}

/**
* Converts PlatformContext to ApplicationContext if possible.
* Otherwise returns the platform context as is.
* @return PlatformContext's applicationContext for Android.
*/
internal actual fun PlatformContext.toApplicationContext(): PlatformContext =
try {
this.applicationContext as PlatformContext
Comment thread
nishatoma marked this conversation as resolved.
Outdated
} catch (exception: Exception) {
// Return the platform context as is just in case.
this
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package coil3

import android.app.Application
import coil3.test.utils.RobolectricTest
import coil3.test.utils.ViewTestActivity
import coil3.test.utils.context
import coil3.test.utils.launchActivity
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertSame
import kotlin.test.assertTrue
Expand Down Expand Up @@ -47,6 +50,31 @@ class SingletonImageLoaderAndroidTest : RobolectricTest() {
assertTrue(factory.isInitialized)
assertFalse((context.applicationContext as TestApplication).isInitialized)
}

@Test
@Config(application = TestApplication::class)
fun `GIVEN activity context, WHEN image loader is set, THEN it uses application context`() {
// GIVEN
var capturedContext: PlatformContext? = null
val factory = SingletonImageLoader.Factory { ctx ->
capturedContext = ctx
ImageLoader(context = capturedContext)
}

SingletonImageLoader.setSafe(factory)

// WHEN
launchActivity { activity: ViewTestActivity ->
SingletonImageLoader.get(activity)
}

// THEN
assertEquals(
expected = context.applicationContext,
actual = capturedContext,
message = "Expected factory to receive Application context, not Activity"
)
}
}

class TestApplication : Application(), SingletonImageLoader.Factory {
Expand Down
11 changes: 8 additions & 3 deletions coil/src/commonMain/kotlin/coil3/SingletonImageLoader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,18 @@ object SingletonImageLoader {
private fun newImageLoader(context: PlatformContext): ImageLoader {
// Local storage to ensure newImageLoader is invoked at most once.
var imageLoader: ImageLoader? = null
// No impact on non-Android platforms, still uses
// same context, but for Android it uses applicationContext when possible.
Comment thread
nishatoma marked this conversation as resolved.
Outdated
val applicationContext = context.toApplicationContext()

return reference.updateAndGet { value ->
when {
value is ImageLoader -> value
imageLoader != null -> imageLoader
else -> {
((value as? Factory)?.newImageLoader(context)
?: context.applicationImageLoaderFactory()?.newImageLoader(context)
?: DefaultSingletonImageLoaderFactory.newImageLoader(context))
((value as? Factory)?.newImageLoader(applicationContext)
?: applicationContext.applicationImageLoaderFactory()?.newImageLoader(applicationContext)
?: DefaultSingletonImageLoaderFactory.newImageLoader(applicationContext))
.also { imageLoader = it }
}
}
Expand All @@ -115,6 +118,8 @@ object SingletonImageLoader {
}
}

internal expect fun PlatformContext.toApplicationContext(): PlatformContext
Comment thread
nishatoma marked this conversation as resolved.
Outdated

internal expect fun PlatformContext.applicationImageLoaderFactory(): Factory?

private val DefaultSingletonImageLoaderFactory = Factory { context ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ package coil3
internal actual fun PlatformContext.applicationImageLoaderFactory(): SingletonImageLoader.Factory? {
return null
}

/**
* @return the PlatformContext as is, for non-Android platform.
*/
internal actual fun PlatformContext.toApplicationContext(): PlatformContext = this