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 남지연 4주차 과제 Step1 #56

Open
wants to merge 9 commits into
base: njiyeon
Choose a base branch
from

Conversation

nJiyeon
Copy link

@nJiyeon nJiyeon commented Jul 18, 2024

과제 수행시 느꼈던 어려움 & 느낀점

  • 계속해서 앱 버그가 발생하여 Logcat으로 오류를 잡는 게 어려웠다.
  • 코드가 계속해서 길어지고 import된 게 많아서 코드에서 수정이 필요한 부분을 확인하는 것이 어려웠다.
  • API 문서를 보는 게 아직 많이 서툴다는 것을 느꼈다.
  • 조원들이 이전에 label을 사용해서 마커표시를 했다는 걸 들어서 그나마 수월하게 과제를 수행할 수 있었다.
  • 앱 버그를 잡는 데 집중하다가 기능 별로 commit을 하는 것을 또 놓쳐서 다음 과제 수행 시에는 이 부분을 신경써야겠다고 느꼈다.

중점적으로 리뷰해주셨으면 하는 부분

  • 코드를 짜다보니 MainActivity가 엄청 길어졌는데, 수정이 필요한 건지 궁금합니다.
  • bottomsheet를 제대로 사용한 게 맞는지 궁금합니다 !
  • step0 리뷰에서 RelativeLayout이 아닌 다른 레이아웃을 사용해보라고 하셨는데, Logcat으로 오류를 확인하며 CoordinatorLayout로 수정하였습니다. 이와 같은 방식으로 수정한 것이 맞을까요?
  • 카카오지도 onMapError() 호출 시 에러 화면을 보여준다는 걸 제가 맞게 이해하고 구현한 것이 맞을까요?
  • Step0 리뷰에서 MyAppication에서 Retrofit을 싱글톤으로 만들어보라고 하신 부분을 제가 맞게 반영한 건지 확인 부탁드립니다 !

Copy link

@mkSpace mkSpace left a comment

Choose a reason for hiding this comment

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

이번주도 고생많으셨습니다!

주차를 진행하면서 코드가 매우 깔끔해진게 느껴지네요! 제가 드리는 피드백 대로 깊은 고민을 하시고 코드를 작성하시는게 보입니다. 이대로 계속 Keep Grinding 하시죠!

리뷰 남겨드리는데 아직은 MVVM 아키텍처와 레이어 별 경계에 대해서 미숙한 부분이 조금 보입니다. 각 객체의 역할과 책임, 의존에 대해 깊이 고민해보는 주차가 되셨으면 좋겠습니다.

리뷰 남겨드리니 의견과 수정 부탁드립니다 ~

private lateinit var locationSearcher: LocationSearcher
private lateinit var keywordViewModel: KeywordViewModel

companion object {
Copy link

Choose a reason for hiding this comment

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

Kotlin convention에서 companio object의 위치는 맨 아래로 지시하고 있습니다. 최하단으로 내리는게 좋겠네요.


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

// 카카오 지도 초기화
locationSearcher = LocationSearcher(this)
Copy link

Choose a reason for hiding this comment

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

LocationSearcher의 getInstance는 언제 쓰는걸까요?

) { result ->
if (result.resultCode == RESULT_OK) {
val data = result.data
data?.let {
Copy link

Choose a reason for hiding this comment

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

에러처리할 때 고민해봐야 할 부분은 데이터를 받지 못한 경우(이 경우에는 검색 데이터를 못 받아온 경우겠네요) 어떤 방식으로 UX를 보장해야 할까?를 고민해 보셔야 할 것 같네요. 현재의 경우라면 (0,0) 포지션으로 이동할 것 같은데 우아하진 않은것 같아요. 이런 경우 Toast Message를 간략히 보여주거나 하는 방식을 사용해 볼 수 있겠네요.
그리고 저는 data?.let 과 같은 scope function은 최대한 짧게 작성하려고 해요. 지금 경우는 매우 길어진 것 같으니 null일 때에 대한 처리를 위에서 하고 depth를 줄이는게 가독성엔 더 좋겠네요.

// 인증 후 API가 정상적으로 실행될 때 호출됨
override fun onMapReady(map: KakaoMap) {
kakaoMap = map
labelLayer = kakaoMap.labelManager?.layer!!
Copy link

Choose a reason for hiding this comment

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

!! 사용은 지양하셔야 합니다.
안드로이드 내에서 이유없는 에러는 정말 빈번합니다. 안드로이드에서 !!는 단숨에 fatal error를 만드는 지뢰같은 표현식입니다. 행여나 그럴 수 있지~ 라는 마인드로 대처하셔야 합니다.

Comment on lines 118 to 123
// 에러 화면 초기화
errorLayout = findViewById(R.id.error_layout)
errorMessage = findViewById(R.id.error_message)
errorDetails = findViewById(R.id.error_details)
retryButton = findViewById(R.id.retry_button)
retryButton.setOnClickListener { onRetryButtonClick() }
Copy link

Choose a reason for hiding this comment

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

이런건 함수로 뺄 수 있겠네요

}

private fun addLabel(placeName: String?, roadAddressName: String?, latitude: Double, longitude: Double) {
if (placeName != null && roadAddressName != null) {
Copy link

Choose a reason for hiding this comment

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

이런 if 문도 줄일 수 있어요

Suggested change
if (placeName != null && roadAddressName != null) {
if (placeName == null || roadAddressName == null) return

private lateinit var errorDetails: TextView
private lateinit var retryButton: ImageButton
private lateinit var kakaoMap: KakaoMap
private lateinit var labelLayer: LabelLayer
Copy link

Choose a reason for hiding this comment

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

labelLayer를 따로 캐싱한 이유가 있을까요?

Comment on lines 208 to 215
val sharedPreferences = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
with(sharedPreferences.edit()) {
putFloat(PREF_LATITUDE, latitude.toFloat())
putFloat(PREF_LONGITUDE, longitude.toFloat())
putString(PREF_PLACE_NAME, placeName)
putString(PREF_ROAD_ADDRESS_NAME, roadAddressName)
apply()
}
Copy link

Choose a reason for hiding this comment

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

SharedPreferences 조작은 View의 역할은 아닙니다. ViewModel이나 Repository 쪽으로 빼는게 좋겠네요

Comment on lines 219 to 237
val sharedPreferences = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
if (sharedPreferences.contains(PREF_LATITUDE) && sharedPreferences.contains(PREF_LONGITUDE)) {
val latitude = sharedPreferences.getFloat(PREF_LATITUDE, 0.0f).toDouble()
val longitude = sharedPreferences.getFloat(PREF_LONGITUDE, 0.0f).toDouble()
val placeName = sharedPreferences.getString(PREF_PLACE_NAME, "") ?: ""
val roadAddressName = sharedPreferences.getString(PREF_ROAD_ADDRESS_NAME, "") ?: ""

if (placeName.isNotEmpty() && roadAddressName.isNotEmpty()) {
Log.d(TAG, "Loaded last marker position: lat=$latitude, lon=$longitude, placeName=$placeName, roadAddressName=$roadAddressName")
addLabel(placeName, roadAddressName, latitude, longitude)
val position = LatLng.from(latitude, longitude)
moveCamera(position)
updateBottomSheet(placeName, roadAddressName)
} else {
Log.d(TAG, "No place name or road address name found")
}
} else {
Log.d(TAG, "No last marker position found in SharedPreferences")
}
Copy link

Choose a reason for hiding this comment

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

MainActivity의 역할을 다하기 위해 SharedPreferences에 값을 저장하는걸 아는것까지가 MainActivity의 책임일지 생각해보시면 이 로직을 어디에 작성해야 할지 경계가 분명해질거에요

Copy link

Choose a reason for hiding this comment

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

SharedPreferences를 View 내에서 직접 로드해서 View에 표현하는게 View의 역할이 아닙니다.
View가 필요한 데이터를 ViewModel에서 내려받아 단순히 표현! 하는게 View의 역할입니다.

Comment on lines -38 to +39
val retrofit = Retrofit.Builder()
.baseUrl(BuildConfig.KAKAO_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
val api = retrofit.create(KakaoLocalApi::class.java)
val api = MyApplication.retrofit.create(KakaoLocalApi::class.java)
Copy link

Choose a reason for hiding this comment

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

Retrofit 생성을 외부로 빼신건 좋은데 아직 api에 대한 인스턴스 취득을 Activity에서 해주고 있네요.
자 그럼 이제 어떻게 해야 할까요? api 사용부는 ViewModel로 옮겼고 인스턴스 생성도 외부로 옮겼는데 아직도 Retrofit 인스턴스에 대한 접근이 필요하다면 의존성이 생기는건데 이를 피할 수 있는 방법이 뭐가 있을까요?
고민 한번 해보심 좋을 것 같네요. 아마 다음 주차에서 배우실 것 같아요 👍

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