Skip to content

[Refactor] KakaoMap 매칭 지도 화면 Compose 전환 #546#549

Open
edv-Shin wants to merge 10 commits into
devfrom
refactor/kakaomap-compose-546
Open

[Refactor] KakaoMap 매칭 지도 화면 Compose 전환 #546#549
edv-Shin wants to merge 10 commits into
devfrom
refactor/kakaomap-compose-546

Conversation

@edv-Shin

@edv-Shin edv-Shin commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

#️⃣연관된 이슈

ex) #이슈번호, #이슈번호

#546

📝작업 내용

이번 PR에서 작업한 내용을 간략히 설명해주세요(이미지 첨부 가능)

Kakao Map SDK v2(com.kakao.vectormap) 기반 매칭 지도 화면(MatchingMapFragment)을 Compose로 전환했습니다.
SDK v2는 공식 Compose 지원이 없어 AndroidView interop으로 MapView를 호스팅하고, 생명주기·카메라 제어를 직접 연결했습니다. 마커/클러스터 로직은 기존 MapViewManager + TED 클러스터링을 그대로 재사용합니다.

  • KakaoMapView Composable 신규 작성 (재사용 컴포넌트)
    • AndroidViewMapView 호스팅, start() + KakaoMapReadyCallback 캡슐화
    • 생명주기(resume/pause/finish)를 DisposableEffect + LifecycleEventObserver로 브리지
    • LocalInspectionMode로 Preview 시 빈 화면 반환
  • MatchingMapScreen Composable 신규 작성
    • combinedMapDatacollectAsStateWithLifecycle로 구독
    • 마커/클러스터 그리기(redrawMarkers)는 명령형 호출이라 LaunchedEffect(mapData, manager)에서 실행
    • managermutableStateOf로 두어 지도 준비(null → 값) 시 다시 그리기
    • 라벨 클릭(클러스터/내 장소) 분기를 콜백으로 상위 위임
  • MatchingMapController 신규 작성
    • Screen 내부에서 비동기 생성되는 MapViewManager에 다리를 놓아, 화면 밖(Fragment)에서 카메라 제어
    • 권한/현재위치/초기 복원처럼 Fragment 가 담당하는 로직이 카메라를 만질 때 사용
  • MatchingMapFragment
    • fragment_matching_map.xmlMapViewComposeView, applyAppTheme로 호스팅
    • 지도/마커/클러스터/카메라 idle은 Screen에 위임
    • 권한·현재위치·초기 카메라 복원·필터·다이얼로그는 Fragment 유지 (카메라만 controller 경유)
  • MatchingMapViewModel
    • initialMapPosition LiveData → StateFlow (.value 호환으로 기존 테스트 통과)

스크린샷 (선택)

💬리뷰 요구사항(선택)

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요?

edv-Shin added 5 commits June 29, 2026 22:11
- AndroidView로 MapView 호스팅, start()/MapReadyCallback 캡슐화, factory 1회 생성
- 생명주기(resume/pause/finish) DisposableEffect + LifecycleEventObserver 브리지
- onMapReady/onMapError 콜백을 상위 Composable로 노출
- KakaoMapView 사용, onMapReady에서 MapViewManager 생성
- collectAsStateWithLifecycle(combinedMapData) + LaunchedEffect로 redrawMarkers 호출
- 카메라 idle: 위치 저장 + 영역 이동 시 fetchMatchingMembersIfMoved
- 라벨 클릭: 클러스터/내 장소 분기를 콜백으로 상위 위임
- 마커 그리기/클러스터 계산은 기존 MapViewManager/ClusterCalculator 재사용
- fragment_matching_map.xml: MapView → ComposeView(MatchingMapScreen)
- 지도/마커/클러스터/라벨클릭을 Screen에 위임, Fragment는 필터·다이얼로그·옵저버 유지
- 현재위치 버튼/초기 카메라 복원은 카메라 제어 통로 필요 → TODO(#546)로 일시 보류
- LiveData<MapPosition?> → StateFlow<MapPosition?>
- Compose에서 일관되게 다루기 위함. .value 호환이라 기존 테스트 무수정 통과
- MatchingMapController 추가: Screen 내부 MapViewManager에 다리를 놓아
  화면 밖(Fragment)에서 moveCamera/currentBounds 호출
- MatchingMapScreen: controller/onMapReady 파라미터 추가, 지도 준비 시 통로 연결
- MatchingMapFragment: 현재위치 버튼·초기 카메라 복원을 controller 경유로 복원
  (권한/FusedLocation은 Fragment 책임 유지)
@edv-Shin edv-Shin changed the title [Refactor] KakaoMap 매칭 지도 화면 Compose 전환 (#546) [Refactor] KakaoMap 매칭 지도 화면 Compose 전환 #546 Jul 2, 2026
@edv-Shin
edv-Shin force-pushed the refactor/kakaomap-compose-546 branch from 2d32884 to 3d21778 Compare July 2, 2026 06:08
호출부가 없는 죽은 코드 정리. moveCamera 는 manager? 로 이미 null-safe 하게
동작하므로 isReady 사전 체크가 불필요하고, 지도 영역은 Screen 의 onCameraIdle
에서 manager.getCurrentBounds() 로 직접 구해 currentBounds() 통로도 쓰이지 않는다.
) {
// Preview 에서는 빈 영역으로 return
if (LocalInspectionMode.current) {
return

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return 도 좋지만, Box나 다른 composable로 modifier를 넘겨줘서 프리뷰를 보는 방법도 있어요

@edv-Shin edv-Shin Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6722a44 수정했습니다!

val lifecycleOwner = LocalLifecycleOwner.current

// recomposition 마다 재생성 방지하기 위해 remember 사용
val mapView = remember { MapView(context) }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

context가 변경되는 경우를 고려해서 아래처럼 구현하면 좋을거 같아요

Suggested change
val mapView = remember { MapView(context) }
val mapView = remember(context) { MapView(context) }

@edv-Shin edv-Shin Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

17a5225 수정했습니다!


override fun onMapError(error: Exception) {
Timber.e(error, "KakaoMap error")
onMapError(error)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 DisposableEffect 내부와 AndroidView 내부에서 onMapReady, onMapError 같은 외부 콜백을 직접 참조하고 있습니다. 만약 이 컴포저블을 호출한 상위 컴포저블이 리컴포지션되면서 onMapReady 람다를 새로 넘겨준다면, factory와 DisposableEffect 내부의 콜백은 처음 생성될 당시의 옛날 람다를 기억하고 작동하게 됩니다. 상위에서 넘겨받는 콜백들을 rememberUpdatedState로 감싸서 언제나 최신 상태를 참조하도록 해주세요.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

58e0626 수정했습니다!

return
@SuppressLint("MissingPermission") // 권한은 isLocationPermissionGranted()로 이미 확인됨
private fun moveToCurrentLocation() {
fusedLocationClient.lastLocation.addOnSuccessListener { location ->

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addOnFailureListener 도 고려하면 좋을거 같네요

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

48e6775
수정했습니다!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants