From a3ad43a40e6a3f0e6350ec70dd0eed3566d38928 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Sat, 8 Jun 2024 21:44:27 +0900 Subject: [PATCH 01/13] Below than api24,use decodeFromString Change-Id: Icf428ebfe7e153e132e112c2dc6926bd40ab3951 --- .../core/network/demo/DemoNiaNetworkDataSource.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt index b7c912c00..0f91e0337 100644 --- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt +++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt @@ -17,6 +17,7 @@ package com.google.samples.apps.nowinandroid.core.network.demo import JvmUnitTestDemoAssetManager +import android.os.Build import com.google.samples.apps.nowinandroid.core.network.Dispatcher import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.IO import com.google.samples.apps.nowinandroid.core.network.NiaNetworkDataSource @@ -28,6 +29,7 @@ import kotlinx.coroutines.withContext import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream +import okio.use import javax.inject.Inject /** @@ -42,13 +44,21 @@ class DemoNiaNetworkDataSource @Inject constructor( @OptIn(ExperimentalSerializationApi::class) override suspend fun getTopics(ids: List?): List = withContext(ioDispatcher) { - assets.open(TOPICS_ASSET).use(networkJson::decodeFromStream) + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + assets.open(TOPICS_ASSET).use(networkJson::decodeFromStream) + } else { + networkJson.decodeFromString(assets.open(TOPICS_ASSET).toString()) + } } @OptIn(ExperimentalSerializationApi::class) override suspend fun getNewsResources(ids: List?): List = withContext(ioDispatcher) { - assets.open(NEWS_ASSET).use(networkJson::decodeFromStream) + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + assets.open(NEWS_ASSET).use(networkJson::decodeFromStream) + } else { + networkJson.decodeFromString(assets.open(TOPICS_ASSET).toString()) + } } override suspend fun getTopicChangeList(after: Int?): List = From 6af76eeea5a29b7b986a17934411e79cbfb53671 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Sat, 8 Jun 2024 23:42:32 +0900 Subject: [PATCH 02/13] Create convertStreamToString. Change-Id: I07dbb58813bc891f407773fddab7f1487f1ed24f --- .../network/demo/DemoNiaNetworkDataSource.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt index 0f91e0337..203a1e0c5 100644 --- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt +++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt @@ -30,7 +30,11 @@ import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream import okio.use +import java.io.ByteArrayOutputStream +import java.io.InputStream +import java.nio.charset.StandardCharsets import javax.inject.Inject +import kotlin.coroutines.coroutineContext /** * [NiaNetworkDataSource] implementation that provides static news resources to aid development @@ -67,6 +71,21 @@ class DemoNiaNetworkDataSource @Inject constructor( override suspend fun getNewsResourceChangeList(after: Int?): List = getNewsResources().mapToChangeList(NetworkNewsResource::id) + private suspend fun convertStreamToString(inputStream: InputStream): String = withContext( + coroutineContext, + ) { + val result = ByteArrayOutputStream() + val buffer = ByteArray(1024) + var length = 0 + while (true) { + length = inputStream.read(buffer) + if (length == -1) break + result.write(buffer, 0, length) + } + + result.toString(StandardCharsets.UTF_8.name()) + } + companion object { private const val NEWS_ASSET = "news.json" private const val TOPICS_ASSET = "topics.json" From 19374bced574dee370a8f5e11eb3836074b39db1 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Sat, 8 Jun 2024 23:44:53 +0900 Subject: [PATCH 03/13] Take capability below API 24, and add comment. Change-Id: I86d99fa9e74a8475c0b2bad202cfb4697ab1016b --- .../core/network/demo/DemoNiaNetworkDataSource.kt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt index 203a1e0c5..eaeafa12d 100644 --- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt +++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt @@ -48,20 +48,26 @@ class DemoNiaNetworkDataSource @Inject constructor( @OptIn(ExperimentalSerializationApi::class) override suspend fun getTopics(ids: List?): List = withContext(ioDispatcher) { - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { assets.open(TOPICS_ASSET).use(networkJson::decodeFromStream) } else { - networkJson.decodeFromString(assets.open(TOPICS_ASSET).toString()) + // Use decodeFromString to capability with API 24 below. + // https://github.com/Kotlin/kotlinx.serialization/issues/2457#issuecomment-1786923342 + val topicsJsonString = convertStreamToString(assets.open(TOPICS_ASSET)) + networkJson.decodeFromString(topicsJsonString) } } @OptIn(ExperimentalSerializationApi::class) override suspend fun getNewsResources(ids: List?): List = withContext(ioDispatcher) { - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { assets.open(NEWS_ASSET).use(networkJson::decodeFromStream) } else { - networkJson.decodeFromString(assets.open(TOPICS_ASSET).toString()) + // Use decodeFromString to capability with API 24 below. + // https://github.com/Kotlin/kotlinx.serialization/issues/2457#issuecomment-1786923342 + val newsJsonString = convertStreamToString(assets.open(NEWS_ASSET)) + networkJson.decodeFromString(newsJsonString) } } From 6649d2086cb8bbe400870562b44a7721294d76aa Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Sat, 8 Jun 2024 23:45:43 +0900 Subject: [PATCH 04/13] Add KDoC for convertStreamToString. Change-Id: Idb7fc085e889f8012234d14ad7bc0a4713073d6e --- .../nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt index eaeafa12d..671197bcc 100644 --- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt +++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt @@ -77,6 +77,9 @@ class DemoNiaNetworkDataSource @Inject constructor( override suspend fun getNewsResourceChangeList(after: Int?): List = getNewsResources().mapToChangeList(NetworkNewsResource::id) + /** + * Convert [InputStream] to [String]. + */ private suspend fun convertStreamToString(inputStream: InputStream): String = withContext( coroutineContext, ) { From c6af7dd0851d1dc47cfdeabc442fca154a6d10ee Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Sat, 8 Jun 2024 23:46:51 +0900 Subject: [PATCH 05/13] Add API 21 to CI. Change-Id: I7e1406da9bf7d8aca44f48d9d7dfeb123d67a562 --- .github/workflows/Build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Build.yaml b/.github/workflows/Build.yaml index 6bee0ddfb..7bbb75e07 100644 --- a/.github/workflows/Build.yaml +++ b/.github/workflows/Build.yaml @@ -153,7 +153,7 @@ jobs: timeout-minutes: 55 strategy: matrix: - api-level: [26, 30] + api-level: [21, 26, 30] steps: - name: Delete unnecessary tools 🔧 From 2e2eaf933ba685d31a8ee90ea13dfa8666b9968a Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Sun, 9 Jun 2024 11:06:16 +0900 Subject: [PATCH 06/13] Remove `okio.use` and redundant length init. Change-Id: Ibac659c7aff6d8be99f52d012d603f8251bbd23d --- .../nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt index 671197bcc..ac6c21739 100644 --- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt +++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt @@ -29,7 +29,6 @@ import kotlinx.coroutines.withContext import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream -import okio.use import java.io.ByteArrayOutputStream import java.io.InputStream import java.nio.charset.StandardCharsets @@ -85,7 +84,7 @@ class DemoNiaNetworkDataSource @Inject constructor( ) { val result = ByteArrayOutputStream() val buffer = ByteArray(1024) - var length = 0 + var length: Int while (true) { length = inputStream.read(buffer) if (length == -1) break From d5c070a6f0f7159ea9e697fc9b1d6507a81f76b5 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Fri, 20 Dec 2024 21:18:31 +0900 Subject: [PATCH 07/13] Create readText method. Change-Id: I15df6f18343bcf36d2d583a19cd47d6344942201 --- .../apps/nowinandroid/core/network/demo/DemoAssetManager.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoAssetManager.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoAssetManager.kt index e5fb07bb3..d3264a251 100644 --- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoAssetManager.kt +++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoAssetManager.kt @@ -18,6 +18,7 @@ package com.google.samples.apps.nowinandroid.core.network.demo import java.io.InputStream -fun interface DemoAssetManager { +interface DemoAssetManager { fun open(fileName: String): InputStream + fun readText(fileName: String): String } From 2e192955900c56508b273eeec92e723420348738 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Fri, 20 Dec 2024 21:18:42 +0900 Subject: [PATCH 08/13] Override readText. Change-Id: Ibf7fca9de5461e7285ed6d68092e36d70408f3bd --- core/network/src/main/kotlin/JvmUnitTestDemoAssetManager.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/network/src/main/kotlin/JvmUnitTestDemoAssetManager.kt b/core/network/src/main/kotlin/JvmUnitTestDemoAssetManager.kt index 2ef418517..7017cb0e2 100644 --- a/core/network/src/main/kotlin/JvmUnitTestDemoAssetManager.kt +++ b/core/network/src/main/kotlin/JvmUnitTestDemoAssetManager.kt @@ -17,6 +17,7 @@ import com.google.samples.apps.nowinandroid.core.network.demo.DemoAssetManager import java.io.File import java.io.InputStream +import java.nio.charset.StandardCharsets import java.util.Properties /** @@ -38,4 +39,5 @@ internal object JvmUnitTestDemoAssetManager : DemoAssetManager { private val assets = File(properties["android_merged_assets"].toString()) override fun open(fileName: String): InputStream = File(assets, fileName).inputStream() + override fun readText(fileName: String): String = File(assets, fileName).readText(StandardCharsets.UTF_8) } From f2b9c4eb0d1adad063cee8b4697a7ca87b276536 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Fri, 20 Dec 2024 21:19:20 +0900 Subject: [PATCH 09/13] Pass new DemoAssetManager with open and readText methods. Change-Id: I4b58c250e76f6d41e794087ff3b467fc61c88eca --- .../apps/nowinandroid/core/network/di/NetworkModule.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt index a97540f2b..08e186d01 100644 --- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt +++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt @@ -32,6 +32,7 @@ import kotlinx.serialization.json.Json import okhttp3.Call import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor +import java.io.InputStream import javax.inject.Singleton @Module @@ -48,7 +49,10 @@ internal object NetworkModule { @Singleton fun providesDemoAssetManager( @ApplicationContext context: Context, - ): DemoAssetManager = DemoAssetManager(context.assets::open) + ): DemoAssetManager = object : DemoAssetManager { + override fun open(fileName: String): InputStream = context.assets.open(fileName) + override fun readText(fileName: String): String = context.assets.open(fileName).bufferedReader().use { it.readText() } + } @Provides @Singleton From 9c443704d287cb8a4e22142906fae41b9a11a291 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Fri, 20 Dec 2024 21:20:02 +0900 Subject: [PATCH 10/13] Replace manual string converter to readText method. Change-Id: If8cc6c27bd399fcdf8446ec411626f13d39e707c --- .../network/demo/DemoNiaNetworkDataSource.kt | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt index ac6c21739..abb2a4b72 100644 --- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt +++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt @@ -29,11 +29,7 @@ import kotlinx.coroutines.withContext import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream -import java.io.ByteArrayOutputStream -import java.io.InputStream -import java.nio.charset.StandardCharsets import javax.inject.Inject -import kotlin.coroutines.coroutineContext /** * [NiaNetworkDataSource] implementation that provides static news resources to aid development @@ -52,7 +48,7 @@ class DemoNiaNetworkDataSource @Inject constructor( } else { // Use decodeFromString to capability with API 24 below. // https://github.com/Kotlin/kotlinx.serialization/issues/2457#issuecomment-1786923342 - val topicsJsonString = convertStreamToString(assets.open(TOPICS_ASSET)) + val topicsJsonString = assets.readText(TOPICS_ASSET) networkJson.decodeFromString(topicsJsonString) } } @@ -65,7 +61,7 @@ class DemoNiaNetworkDataSource @Inject constructor( } else { // Use decodeFromString to capability with API 24 below. // https://github.com/Kotlin/kotlinx.serialization/issues/2457#issuecomment-1786923342 - val newsJsonString = convertStreamToString(assets.open(NEWS_ASSET)) + val newsJsonString = assets.readText(NEWS_ASSET) networkJson.decodeFromString(newsJsonString) } } @@ -76,24 +72,6 @@ class DemoNiaNetworkDataSource @Inject constructor( override suspend fun getNewsResourceChangeList(after: Int?): List = getNewsResources().mapToChangeList(NetworkNewsResource::id) - /** - * Convert [InputStream] to [String]. - */ - private suspend fun convertStreamToString(inputStream: InputStream): String = withContext( - coroutineContext, - ) { - val result = ByteArrayOutputStream() - val buffer = ByteArray(1024) - var length: Int - while (true) { - length = inputStream.read(buffer) - if (length == -1) break - result.write(buffer, 0, length) - } - - result.toString(StandardCharsets.UTF_8.name()) - } - companion object { private const val NEWS_ASSET = "news.json" private const val TOPICS_ASSET = "topics.json" From 75fa949c40cb3039c7ece6a4acb8efaf61f01a3a Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Sat, 21 Dec 2024 16:11:24 +0900 Subject: [PATCH 11/13] Revert exposed `readText` method. Change-Id: I8076fabed4b4f2f460c74b43ad1c3e38a5268005 --- core/network/src/main/kotlin/JvmUnitTestDemoAssetManager.kt | 2 -- .../apps/nowinandroid/core/network/demo/DemoAssetManager.kt | 3 +-- .../apps/nowinandroid/core/network/di/NetworkModule.kt | 6 +----- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/core/network/src/main/kotlin/JvmUnitTestDemoAssetManager.kt b/core/network/src/main/kotlin/JvmUnitTestDemoAssetManager.kt index 7017cb0e2..2ef418517 100644 --- a/core/network/src/main/kotlin/JvmUnitTestDemoAssetManager.kt +++ b/core/network/src/main/kotlin/JvmUnitTestDemoAssetManager.kt @@ -17,7 +17,6 @@ import com.google.samples.apps.nowinandroid.core.network.demo.DemoAssetManager import java.io.File import java.io.InputStream -import java.nio.charset.StandardCharsets import java.util.Properties /** @@ -39,5 +38,4 @@ internal object JvmUnitTestDemoAssetManager : DemoAssetManager { private val assets = File(properties["android_merged_assets"].toString()) override fun open(fileName: String): InputStream = File(assets, fileName).inputStream() - override fun readText(fileName: String): String = File(assets, fileName).readText(StandardCharsets.UTF_8) } diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoAssetManager.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoAssetManager.kt index d3264a251..e5fb07bb3 100644 --- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoAssetManager.kt +++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoAssetManager.kt @@ -18,7 +18,6 @@ package com.google.samples.apps.nowinandroid.core.network.demo import java.io.InputStream -interface DemoAssetManager { +fun interface DemoAssetManager { fun open(fileName: String): InputStream - fun readText(fileName: String): String } diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt index 08e186d01..a97540f2b 100644 --- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt +++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt @@ -32,7 +32,6 @@ import kotlinx.serialization.json.Json import okhttp3.Call import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor -import java.io.InputStream import javax.inject.Singleton @Module @@ -49,10 +48,7 @@ internal object NetworkModule { @Singleton fun providesDemoAssetManager( @ApplicationContext context: Context, - ): DemoAssetManager = object : DemoAssetManager { - override fun open(fileName: String): InputStream = context.assets.open(fileName) - override fun readText(fileName: String): String = context.assets.open(fileName).bufferedReader().use { it.readText() } - } + ): DemoAssetManager = DemoAssetManager(context.assets::open) @Provides @Singleton From 788c2bdff4099864997e14910d6b9da34f295afa Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Sat, 21 Dec 2024 16:12:12 +0900 Subject: [PATCH 12/13] Create `getDemoDataFromJson` method and use it. Change-Id: I19336b061e74a378cc70470fbd6af8ee4c7533e0 --- .../network/demo/DemoNiaNetworkDataSource.kt | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt index abb2a4b72..5d04ee4c8 100644 --- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt +++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt @@ -17,7 +17,8 @@ package com.google.samples.apps.nowinandroid.core.network.demo import JvmUnitTestDemoAssetManager -import android.os.Build +import android.os.Build.VERSION.SDK_INT +import android.os.Build.VERSION_CODES.N import com.google.samples.apps.nowinandroid.core.network.Dispatcher import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.IO import com.google.samples.apps.nowinandroid.core.network.NiaNetworkDataSource @@ -29,6 +30,7 @@ import kotlinx.coroutines.withContext import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream +import java.io.BufferedReader import javax.inject.Inject /** @@ -40,31 +42,11 @@ class DemoNiaNetworkDataSource @Inject constructor( private val assets: DemoAssetManager = JvmUnitTestDemoAssetManager, ) : NiaNetworkDataSource { - @OptIn(ExperimentalSerializationApi::class) override suspend fun getTopics(ids: List?): List = - withContext(ioDispatcher) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - assets.open(TOPICS_ASSET).use(networkJson::decodeFromStream) - } else { - // Use decodeFromString to capability with API 24 below. - // https://github.com/Kotlin/kotlinx.serialization/issues/2457#issuecomment-1786923342 - val topicsJsonString = assets.readText(TOPICS_ASSET) - networkJson.decodeFromString(topicsJsonString) - } - } + getDemoDataFromJson(TOPICS_ASSET) - @OptIn(ExperimentalSerializationApi::class) override suspend fun getNewsResources(ids: List?): List = - withContext(ioDispatcher) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - assets.open(NEWS_ASSET).use(networkJson::decodeFromStream) - } else { - // Use decodeFromString to capability with API 24 below. - // https://github.com/Kotlin/kotlinx.serialization/issues/2457#issuecomment-1786923342 - val newsJsonString = assets.readText(NEWS_ASSET) - networkJson.decodeFromString(newsJsonString) - } - } + getDemoDataFromJson(NEWS_ASSET) override suspend fun getTopicChangeList(after: Int?): List = getTopics().mapToChangeList(NetworkTopic::id) @@ -72,6 +54,23 @@ class DemoNiaNetworkDataSource @Inject constructor( override suspend fun getNewsResourceChangeList(after: Int?): List = getNewsResources().mapToChangeList(NetworkNewsResource::id) + /** + * Get Demo data form a [fileName] Json file. + */ + @OptIn(ExperimentalSerializationApi::class) + private suspend inline fun getDemoDataFromJson(fileName: String): List = + withContext(ioDispatcher) { + assets.open(fileName).use { inputStream -> + if (SDK_INT >= N) { + networkJson.decodeFromStream(inputStream) + } // https://github.com/Kotlin/kotlinx.serialization/issues/2457#issuecomment-1786923342 + else { + inputStream.bufferedReader().use(BufferedReader::readText) + .let(networkJson::decodeFromString) + } + } + } + companion object { private const val NEWS_ASSET = "news.json" private const val TOPICS_ASSET = "topics.json" From 62086eaa5f16bd08ce6798559635daac68066e9b Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 6 Jan 2025 17:16:47 +0000 Subject: [PATCH 13/13] Refactor change to make it clearer when the deserialization workaround is required. --- .../network/demo/DemoNiaNetworkDataSource.kt | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt index 5d04ee4c8..328cc4e0f 100644 --- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt +++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt @@ -18,7 +18,7 @@ package com.google.samples.apps.nowinandroid.core.network.demo import JvmUnitTestDemoAssetManager import android.os.Build.VERSION.SDK_INT -import android.os.Build.VERSION_CODES.N +import android.os.Build.VERSION_CODES.M import com.google.samples.apps.nowinandroid.core.network.Dispatcher import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.IO import com.google.samples.apps.nowinandroid.core.network.NiaNetworkDataSource @@ -43,10 +43,10 @@ class DemoNiaNetworkDataSource @Inject constructor( ) : NiaNetworkDataSource { override suspend fun getTopics(ids: List?): List = - getDemoDataFromJson(TOPICS_ASSET) + getDataFromJsonFile(TOPICS_ASSET) override suspend fun getNewsResources(ids: List?): List = - getDemoDataFromJson(NEWS_ASSET) + getDataFromJsonFile(NEWS_ASSET) override suspend fun getTopicChangeList(after: Int?): List = getTopics().mapToChangeList(NetworkTopic::id) @@ -55,18 +55,22 @@ class DemoNiaNetworkDataSource @Inject constructor( getNewsResources().mapToChangeList(NetworkNewsResource::id) /** - * Get Demo data form a [fileName] Json file. + * Get data from the given JSON [fileName]. */ @OptIn(ExperimentalSerializationApi::class) - private suspend inline fun getDemoDataFromJson(fileName: String): List = + private suspend inline fun getDataFromJsonFile(fileName: String): List = withContext(ioDispatcher) { assets.open(fileName).use { inputStream -> - if (SDK_INT >= N) { - networkJson.decodeFromStream(inputStream) - } // https://github.com/Kotlin/kotlinx.serialization/issues/2457#issuecomment-1786923342 - else { + if (SDK_INT <= M) { + /** + * On API 23 (M) and below we must use a workaround to avoid an exception being + * thrown during deserialization. See: + * https://github.com/Kotlin/kotlinx.serialization/issues/2457#issuecomment-1786923342 + */ inputStream.bufferedReader().use(BufferedReader::readText) .let(networkJson::decodeFromString) + } else { + networkJson.decodeFromStream(inputStream) } } }