Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android에서 LifeCycle 변화시에 예상치 못하게 지도가 제대로 보이지 않는 문제 #53

Closed
MinJun-chl opened this issue Mar 15, 2023 · 18 comments
Labels

Comments

@MinJun-chl
Copy link

MinJun-chl commented Mar 15, 2023

실행 환경 : 갤럭시 노트 10
사용 버전 : ^1.0.0-dev8
재현 조건 :

  1. NaverMap이 있는 화면(이하, A)에서 다른 화면(이하, B)으로 Navigator.push,
  2. B에서 ImagePicker에서 Image를 선택
  3. A에 있던 지도의 Snapshot이 B화면에 보여지는 현상이 있습니다.
    상호작용이 되지 않는 것으로 보아 이미지가 덮어씌워진 것으로 보이며 해당 로그를 뱉습니다.
ismultisplithandlerrequested: windowingmode=1 isfullscreen=true ispopover=false ishidden=false skipactivitytype=false ishandlertype=true this: decorview@2f08891[mainactivity]

이후 Navigator.pop을 통해 A화면으로 나가보면 A화면에 있던 NaverMap은 dispose되어 격자이미지만 내보냅니다. 이 경우, 어떤 경우에도 Navermap이 다시 init되지 않습니다. (+ 해당 현상이 이 스레드에서 다루는 이슈입니다. -note11g)

224951435-625953fa-cdd0-413a-9e0b-15668b6c8d3a

상기 화면은 imagepicker를 통해 이미지를 등록한 이후의 화면입니다.

@note11g
Copy link
Owner

note11g commented Mar 15, 2023

@MinJun-chl
재현을 위해 최소 재현 가능 예제를 공유해주시길 부탁드리겠습니다.
Github Repo / GIthub Gist 등을 이용해주시면 됩니다. 감사합니다.

@MinJun-chl
Copy link
Author

예제는 제작중에 있습니다.
추가 사항으로 갤럭시 S8+, 안드로이드 버전 9, pie에서는 해당 이슈가 발생하지 않았고
마찬가지로 갤럭시 노트10, 버전 12, API level 31에서는 이슈가 발생했습니다. 모두 실제 단말입니다.

@note11g
Copy link
Owner

note11g commented Mar 16, 2023

@MinJun-chl 최소 재현 가능 예제 완성 후, 링크와 함께 멘션 부탁드리겠습니다!
감사합니다:)

@wnsgh78b
Copy link
Contributor

wnsgh78b commented Mar 16, 2023

너무 좋은 라이브러리 항상 감사히 쓰고있습니다.. ㅎ

저도 비슷한 문제가 발생했습니다.
저의 경우는 앱 테마 변경 때문에 다시 지도 페이지 위젯 다시 빌드시 문제가 생기네요.
문제가 생길시 생명주기에 로그 찍어본 결과입니다.

I/FlutterNaverMap(13849): 네이버맵 reload 4129
I/FlutterNaverMap(13849): 네이버맵 Paused 4129
I/FlutterNaverMap(13849): 네이버맵 Stopped 4129

-> 다크모드로 테마 변경하여 다시 빌드 호출후

I/FlutterNaverMap(13849): 네이버맵 reload 4129
I/FlutterNaverMap(13849): 네이버맵 dispose
I/FlutterNaverMap(13849): 네이버맵 reload 3584

옆의 숫자는 랜덤으로 찍은 객체 고유번호 입니다.

위 로그후 문제 되는 부분은 윗분이 올려주신 스크린샷이랑 같습니다.

사용 버전 : ^1.0.0-dev8
실행 환경 : 갤럭시 s20+ os13 버전

@note11g
Copy link
Owner

note11g commented Mar 16, 2023

@wnsgh78b @MinJun-chl
임시 방편으로, dev7 버전을 사용하시면 메모리 누수 문제는 있지만 해당 문제는 없을 것 같습니다.
해결 방법을 찾을 때까지 dev7 버전을 사용해주시면 좋을 것 같습니다.

@note11g note11g changed the title Android에서 NaverMap과 ImagePicker를 동시에 사용시 문제가 발생합니다. Android에서 LifeCycle에 따라 비정상적으로 NaverMap이 dispose되는 문제 Mar 16, 2023
@note11g
Copy link
Owner

note11g commented Mar 16, 2023

분석한 원인은 다음과 같습니다.

  1. 지도 위젯이 dispose 됨
  2. 그에 따라, onPause, onStop, onDestory를 통하여 지도 객체의 데이터를 메모리에서 해제.
  3. 그러나, Flutter는 single activity이므로, 모든 지도 위젯에 대한 NaverMapView/NaverMap 객체는 동일 activity에 있음.
  4. 현재 플러터에 남아있는 모든 지도 위젯 역시 1에서 실행된 onPause, onStop, onDestory로 인하여 영향을 받게 됨.

메모리 누수를 막으면서 해결하는 방법을 찾고 있습니다. 조금만 기다려주시기 바랍니다.

  • fragment를 이용하는 방법은 실패하였습니다.

@note11g note11g changed the title Android에서 LifeCycle에 따라 비정상적으로 NaverMap이 dispose되는 문제 Android에서 dispose가 예상치 못하게 실행되어 지도 객체가 보이지 않는 문제 Mar 16, 2023
@note11g note11g changed the title Android에서 dispose가 예상치 못하게 실행되어 지도 객체가 보이지 않는 문제 Android에서 dispose가 예상치 못하게 실행되어 지도가 제대로 보이지 않는 문제 Mar 16, 2023
@note11g
Copy link
Owner

note11g commented Mar 18, 2023

@wnsgh78b 안녕하세요. 해당 현상을 동일하게 재현하는데 어려움이 있어, 혹시 테마를 어떤식으로 변경하시는지 알 수 있을까요?
플러터 ThemeData를 이용하여 바꾸시는지, 아니라면 어떤 것을 이용하시는지 알고 싶습니다.
괜찮으시다면 코드 예제도 간단하게 부탁드리겠습니다.
그리고, dev7 버전을 사용하셨을 때 해당 증상 확인되는지 여부도 부탁드리겠습니다.

@note11g note11g pinned this issue Mar 19, 2023
@note11g
Copy link
Owner

note11g commented Mar 20, 2023

@MinJun-chl 3번으로 말씀주신 이슈는 #56 과 유사해보입니다.
해당 이슈의 임시 해결법을 적용해보시겠어요?

@MinJun-chl
Copy link
Author

Visibility를 이용해서 visible : false로 설정하면 해결되긴 합니다만, 이것도 임시인 것 같고,
말씀해주신 방법도 유효한 것으로 확인됩니다.

@note11g
Copy link
Owner

note11g commented Mar 22, 2023

hot-restart시에 간헐적으로 해당 현상 발생

@note11g note11g changed the title Android에서 dispose가 예상치 못하게 실행되어 지도가 제대로 보이지 않는 문제 Android에서 예상치 못하게 dispose 되어 지도가 제대로 보이지 않는 문제 Mar 25, 2023
@note11g
Copy link
Owner

note11g commented Mar 27, 2023

flutter/flutter#40284
이 이슈와도 관련이 있는 것 같습니다.

override fun onActivityResumed(activity: Activity) {
if (activity != this.activity) return
reloadMap()
mapView.onResume()
}
private fun reloadMap() {
if (this::naverMap.isInitialized) {
val nowMapType = naverMap.mapType
naverMap.mapType = NaverMap.MapType.None
naverMap.mapType = nowMapType
}
}

처럼 해결했었으나,

flutter/flutter#40284 (comment)
flutter/flutter#40284 (comment)
최근 추가된 두 코멘트를 봤을 때, 연관성이 있다고 판단됩니다.

@note11g
Copy link
Owner

note11g commented Mar 27, 2023

hot-restart시에 간헐적으로 해당 현상 발생

lifecycle changed -> 다시 앱으로 복귀 -> hot-restart 시에 해당 현상 재현됨

새로 생성되는 맵 객체가 destroy 된 것은 아님. 무엇이 문제인지 확인 필요.

@note11g
Copy link
Owner

note11g commented Mar 28, 2023

추가 사항으로 갤럭시 S8+, 안드로이드 버전 9, pie에서는 해당 이슈가 발생하지 않았고
마찬가지로 갤럭시 노트10, 버전 12, API level 31에서는 이슈가 발생했습니다. 모두 실제 단말입니다.

현재 확인된 사항은, Android 12, 13 (API 31~33)에서 재현됩니다.
Android 10, 11(API 29, 30) 확인 후 다시 코멘트 추가하겠습니다.

@note11g note11g changed the title Android에서 예상치 못하게 dispose 되어 지도가 제대로 보이지 않는 문제 Android에서 LifeCycle 변화시에 예상치 못하게 지도가 제대로 보이지 않는 문제 Mar 28, 2023
@note11g
Copy link
Owner

note11g commented Mar 28, 2023

API 27, 28, 29, 30에서도 동일 현상 확인하였습니다.
또한, 현재 생성 되어있는 맵 위젯만 그런 것이 아닌, 새로 만들어지는 모든 위젯이 동일한 현상이 발생합니다.

일단은, Debug 모드에서 Hot-Restart시에 발생하는 것을 확인하였으나, Release 모드에서는 어떨지 모릅니다.

@wnsgh78b @MinJun-chl
Release 모드에서도 발생하는지 확인 부탁드립니다.
+자체적으로 확인되었습니다.

@note11g
Copy link
Owner

note11g commented Mar 28, 2023

재현 방법을 찾았습니다.

준비사항

  • NaverMap 위젯이 존재하지 않는 페이지 (이하, StartPage라고 하겠습니다)
  • NaverMap 위젯이 존재하는 페이지 (이하, MapPage라고 하겠습니다)

재현 단계

  1. StartPage로 시작합니다.
  2. StartPage -> MapPage로 이동합니다. (push)
  3. MapPage가 띄워지면, LifeCycle가 변화되는 행동을 취합니다. (ex. 갤러리 열기, 다른 앱으로 전환하기, 홈화면으로 가기, 디스플레이 끄기 등)
  4. MapPage를 종료합니다. (pop)
  5. 이제, 새로 생성되는 모든 NaverMap은 격자만 뜨고, 실제 지도는 뜨지 않습니다. (새로 MapPage를 열어서 확인할 수 있습니다)

분석한 원인 및 대책

플러터를 사용할 경우, 안드로이드에서는 앱에서 잠시 나갔다 들어오면, 대부분 아래와 같은 lifeCycle을 탑니다.
(시간과 관련 없음, 실험 과정에서 100% 해당 라이프 사이클을 돌았음)
onPause -> onStop -> onSaveInstanceState -> onStart -> onResume

출처 (출처의 사진에 설명을 위해 약간의 수정을 가했습니다)

그리고 이런 lifeCycle을 탈때마다, onPause에서는 mapView.onPause()를 onResume에서는 mapView.onResume()을 실행하는 것이 Naver Maps Android SDK의 권장사항입니다.
이는, onStop과 onDestroy 역시 예외는 아닙니다.

하지만, 플러터에서 위젯이나 페이지가 dispose 되는 것은 Android lifeCycle과 전혀 관련이 없습니다. (일종의 SingleActivity이기 때문입니다)
따라서, 램 누수를 방지하기 위해서는 마치 activity가 종료되는 것처럼 다음 코드를 dispose시에 실행시켜 주어야 합니다.

override fun dispose() {
    // some codes...
    mapView.onPause() // 정리 작업을 하지 않는 것으로 보여, 수행하지 않아도 괜찮을 것 같음
    mapView.onStop()
    mapView.onDestroy()
    // some codes...
}

그런데, 이슈가 발생하는 조건은

onPause -> onStop -> onSaveInstanceState -> onStart -> onResume (재현 단계의 3번입니다)

가 실행된 이후에 dispose에서 mapView.onStop()이 실행되었을 경우입니다.

생각나는 해결 방안으로는 두가지가 있을 것 같습니다.

  1. dispose에서 mapView.onStop()을 실행하지 않는 방법 (실제로 이슈가 발생하지 않습니다.)
  2. lifeCycle에 따라 실행하지 않는 방법 (lifeCycle을 타지 않으면, 이슈가 발생하지 않으므로)

하지만, 1번으로 해결할 경우, 앞서 설명한 이유로 메모리 누수가 발생하므로, 적용하기에 적절치 않습니다.
따라서, 2번이 효과가 있는지 확인 후에 다시 코멘트 드리도록 하겠습니다.

@note11g note11g changed the title Android에서 LifeCycle 변화시에 예상치 못하게 지도가 제대로 보이지 않는 문제 Android에서 LifeCycle 변화시에 예상치 못하게 지도가 제대로 보이지 않는 문제 Mar 28, 2023
@note11g note11g changed the title Android에서 LifeCycle 변화시에 예상치 못하게 지도가 제대로 보이지 않는 문제 Android에서 LifeCycle 변화시에 예상치 못하게 지도가 제대로 보이지 않는 문제 Mar 28, 2023
@note11g
Copy link
Owner

note11g commented Mar 28, 2023

위의 재현단계를 토대로 2번 해결법을 확인한 결과입니다.

기존 실행 메서드
onPause(), onStop(), onSaveInstanceState(), onStart(), onResume() (각 라이프사이클마다 실행됨)

1. 모두 실행하지 않을 경우
효과 있음
2. onStart()를 실행할 경우
다른 함수와 상관없이 해당 이슈 그대로 발생
3. onStop()을 실행할 경우
해당 이슈에 효과는 있으나, dispose 시키지 않고 단순히 다시 복귀만 했을 경우 까만 화면이 뜨는 이슈가 발생
(lightness, backgroundColor옵션과 관련 없음)

(나머지 모든 케이스 실험해보았습니다.)

결과를 토대로 확인했을 때, 이 이슈를 발생시키려면 (내부 소스를 알 수 없기에 정확히 알 수는 없지만)
onStop() 이 실행되고, onStart() 실행된 후, onStop()한번 더 실행될 때 발생하는 것으로 보입니다.

추측컨대, 앱의 메모리 사용량을 줄이려고 onStop, onSaveInstanceState가 메모리를 정리해주고, onStart를 통해서 메모리를 다시 복구 시켜주는 것 같습니다.
하지만, NaverMap 위젯이 dispose 되며 onStop()이 한번 더 실행되는 바람에, 이때, 예상치 못하게 액티비티의 모든 정보를 정리해버리는 것 같습니다. (실험 결과, onDestroy() 메서드는 관련이 없어보입니다.)

결국, onStart()와 onStop()을 빼고 사용하면 될 것 같습니다.

다음은 라이프사이클에 따른 메서드 실행 관련 메모리 누수 실험 결과입니다.

  • 각 3회씩 시행 후 중앙 값
  • 소수점은 반올림
  • 단위는 MB
구분 맵 켜기 전 맵 켠 후 홈으로 나갔을때 복귀 참고사항
모두 실행 250 565 459 489 dev.8에서 사용한 방식, 이슈 발생
onStart 없이 253 556 433 435 검은화면 이슈
onStart, onStop 없이 252 534 411 472 이슈 없음 (best)
onStart, onStop, onSaveInstanceState 없이 251 536 434 492 이슈 없음

결과에 따라, onStart, onStop 메서드만 실행하지 않는 해결 방법을 적용하겠습니다.

note11g added a commit that referenced this issue Mar 28, 2023
note11g added a commit that referenced this issue Mar 28, 2023
note11g added a commit that referenced this issue Mar 28, 2023
fix issue #53
@note11g
Copy link
Owner

note11g commented Mar 28, 2023

dev.9 버전에서 해결될 예정입니다.
감사합니다.

@note11g
Copy link
Owner

note11g commented Mar 30, 2023

@wnsgh78b @MinJun-chl dev9에서의 수정이 잘못 이루어졌습니다.
재수정이 Dev Preview 10에서 이루어졌으므로, 해당 버전으로 업데이트하시는 것을 권장드립니다. 감사합니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants