Skip to content

Commit daba28e

Browse files
committed
[fix] #60 네트워크 브랜드 이미지 캐싱 로직 변경
1 parent 989516f commit daba28e

5 files changed

Lines changed: 47 additions & 50 deletions

File tree

feature/map/impl/src/main/java/com/neki/android/feature/map/impl/MapContract.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
package com.neki.android.feature.map.impl
22

3+
import androidx.compose.ui.graphics.ImageBitmap
34
import com.neki.android.core.model.Brand
45
import com.neki.android.core.model.PhotoBooth
56
import com.neki.android.feature.map.impl.const.DirectionApp
67
import kotlinx.collections.immutable.ImmutableList
8+
import kotlinx.collections.immutable.ImmutableMap
79
import kotlinx.collections.immutable.persistentListOf
10+
import kotlinx.collections.immutable.persistentMapOf
811

912
data class MapState(
1013
val isLoading: Boolean = false,
1114
val currentLocLatLng: LocLatLng? = null,
1215
val isCameraOnCurrentLocation: Boolean = false,
1316
val dragLevel: DragLevel = DragLevel.FIRST,
1417
val brands: ImmutableList<Brand> = persistentListOf(),
18+
val brandImageCache: ImmutableMap<String, ImageBitmap> = persistentMapOf(),
1519
val mapMarkers: ImmutableList<PhotoBooth> = persistentListOf(),
1620
val nearbyPhotoBooths: ImmutableList<PhotoBooth> = persistentListOf(),
1721
val isShowInfoDialog: Boolean = false,

feature/map/impl/src/main/java/com/neki/android/feature/map/impl/MapScreen.kt

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import androidx.compose.runtime.rememberCoroutineScope
1616
import androidx.compose.runtime.setValue
1717
import androidx.compose.ui.Alignment
1818
import androidx.compose.ui.Modifier
19-
import androidx.compose.ui.graphics.ImageBitmap
2019
import androidx.compose.ui.platform.LocalContext
2120
import androidx.compose.ui.unit.dp
2221
import androidx.compose.ui.window.DialogProperties
@@ -51,7 +50,6 @@ import com.neki.android.feature.map.impl.component.PhotoBoothMarker
5150
import com.neki.android.feature.map.impl.component.ToMapChip
5251
import com.neki.android.feature.map.impl.const.MapConst
5352
import com.neki.android.feature.map.impl.util.DirectionHelper
54-
import com.neki.android.feature.map.impl.util.rememberCachedBrandImage
5553
import kotlinx.coroutines.launch
5654

5755
@OptIn(ExperimentalNaverMapApi::class)
@@ -72,7 +70,6 @@ fun MapRoute(
7270
MapConst.DEFAULT_ZOOM_LEVEL,
7371
)
7472
}
75-
val brandImageCache = rememberCachedBrandImage(uiState.brands)
7673
var isNavigatedToSettings by remember { mutableStateOf(false) }
7774

7875
val locationPermissionLauncher = rememberLauncherForActivityResult(
@@ -185,7 +182,6 @@ fun MapRoute(
185182
onIntent = viewModel.store::onIntent,
186183
locationTrackingMode = locationTrackingMode,
187184
cameraPositionState = cameraPositionState,
188-
brandImageCache = brandImageCache,
189185
)
190186
}
191187

@@ -198,7 +194,6 @@ fun MapScreen(
198194
cameraPositionState: CameraPositionState = rememberCameraPositionState {
199195
position = CameraPosition(LatLng(MapConst.DEFAULT_LATITUDE, MapConst.DEFAULT_LONGITUDE), MapConst.DEFAULT_ZOOM_LEVEL)
200196
},
201-
brandImageCache: Map<String, ImageBitmap> = emptyMap(),
202197
) {
203198
val mapProperties = remember(locationTrackingMode) {
204199
MapProperties(
@@ -227,11 +222,9 @@ fun MapScreen(
227222
},
228223
) {
229224
uiState.mapMarkers.filter { it.isCheckedBrand }.forEach { photoBooth ->
230-
val cachedBitmap = brandImageCache[photoBooth.imageUrl]
231225
PhotoBoothMarker(
232226
photoBooth = photoBooth,
233-
isFocused = photoBooth.isFocused,
234-
cachedBitmap = cachedBitmap,
227+
cachedBitmap = uiState.brandImageCache[photoBooth.imageUrl],
235228
onClick = {
236229
onIntent(MapIntent.ClickPhotoBoothMarker(LocLatLng(photoBooth.latitude, photoBooth.longitude)))
237230
},

feature/map/impl/src/main/java/com/neki/android/feature/map/impl/MapViewModel.kt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,15 @@ package com.neki.android.feature.map.impl
22

33
import android.annotation.SuppressLint
44
import android.content.Context
5+
import androidx.compose.ui.graphics.ImageBitmap
6+
import androidx.compose.ui.graphics.asImageBitmap
57
import androidx.lifecycle.ViewModel
68
import androidx.lifecycle.viewModelScope
9+
import coil3.ImageLoader
10+
import coil3.request.ImageRequest
11+
import coil3.request.SuccessResult
12+
import coil3.request.allowHardware
13+
import coil3.toBitmap
714
import com.google.android.gms.location.LocationServices
815
import com.google.android.gms.location.Priority
916
import com.google.android.gms.tasks.CancellationTokenSource
@@ -19,7 +26,10 @@ import com.neki.android.feature.map.impl.util.calculateDistance
1926
import dagger.hilt.android.lifecycle.HiltViewModel
2027
import dagger.hilt.android.qualifiers.ApplicationContext
2128
import kotlinx.collections.immutable.toImmutableList
29+
import kotlinx.collections.immutable.toImmutableMap
30+
import kotlinx.coroutines.Dispatchers
2231
import kotlinx.coroutines.launch
32+
import kotlinx.coroutines.withContext
2333
import javax.inject.Inject
2434

2535
@HiltViewModel
@@ -283,13 +293,43 @@ class MapViewModel @Inject constructor(
283293
mapRepository.getBrands()
284294
.onSuccess { loadedBrands ->
285295
reduce { copy(isLoading = false, brands = loadedBrands.toImmutableList()) }
296+
cacheBrandImages(loadedBrands, reduce)
286297
}
287298
.onFailure {
288299
reduce { copy(isLoading = false) }
289300
}
290301
}
291302
}
292303

304+
private fun cacheBrandImages(
305+
brands: List<Brand>,
306+
reduce: (MapState.() -> MapState) -> Unit,
307+
) {
308+
viewModelScope.launch {
309+
val imageLoader = ImageLoader(context)
310+
val cache = mutableMapOf<String, ImageBitmap>()
311+
312+
brands.forEach { brand ->
313+
if (brand.imageUrl.isNotEmpty()) {
314+
val request = ImageRequest.Builder(context)
315+
.data(brand.imageUrl)
316+
.allowHardware(false)
317+
.build()
318+
319+
val result = withContext(Dispatchers.IO) {
320+
imageLoader.execute(request)
321+
}
322+
323+
if (result is SuccessResult) {
324+
cache[brand.imageUrl] = result.image.toBitmap().asImageBitmap()
325+
}
326+
}
327+
}
328+
329+
reduce { copy(brandImageCache = cache.toImmutableMap()) }
330+
}
331+
}
332+
293333
private fun loadNearbyPhotoBooths(
294334
longitude: Double?,
295335
latitude: Double?,

feature/map/impl/src/main/java/com/neki/android/feature/map/impl/component/PhotoBoothMarker.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,11 @@ import com.neki.android.feature.map.impl.const.MapConst.MARKER_TRIANGLE_WIDTH
4646
@Composable
4747
internal fun PhotoBoothMarker(
4848
photoBooth: PhotoBooth,
49-
isFocused: Boolean = false,
5049
cachedBitmap: ImageBitmap? = null,
5150
onClick: () -> Unit = {},
5251
) {
5352
MarkerComposable(
54-
keys = arrayOf("$isFocused", photoBooth.imageUrl, "${cachedBitmap != null}"),
53+
keys = arrayOf("${photoBooth.id}", "${photoBooth.isFocused}", "$cachedBitmap"),
5554
state = rememberUpdatedMarkerState(
5655
position = LatLng(photoBooth.latitude, photoBooth.longitude),
5756
),
@@ -65,7 +64,7 @@ internal fun PhotoBoothMarker(
6564
) {
6665
PhotoBoothMarkerContent(
6766
cachedBitmap = cachedBitmap,
68-
isFocused = isFocused,
67+
isFocused = photoBooth.isFocused,
6968
)
7069
}
7170
}

feature/map/impl/src/main/java/com/neki/android/feature/map/impl/util/BrandImageCache.kt

Lines changed: 0 additions & 39 deletions
This file was deleted.

0 commit comments

Comments
 (0)