-
Notifications
You must be signed in to change notification settings - Fork 33
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_이아림_1주차과제 #8
base: arieum
Are you sure you want to change the base?
Conversation
arieum
commented
Jun 27, 2024
•
edited
Loading
edited
- UI가 생각보다 고역이었습니다. 리니어레이아웃에서 두 텍스트뷰를 양끝단에 두기위해 space공간을 두는점, softkeyboard가 화면을 가리지 않게 하기 위해 manifest를 수정해야 했던점... 이러한 사소한 부분들이 발목을 많이 잡았습니다
- 역시나 RecyclerView+Adapter를 구현하는 게 만만치 않았습니다 동시에 Intent도 자칫 잘못하면 갑자기 다른 화면으로 넘어가 난행이었던 것 같습니다
- 코드 작성하면서 느꼈지만, 내가 클래스명을 지었음에도 계속해서 헷갈렸던것 같습니다. 어떤 클래스가 어떤 기능을 하는지 한눈에 알 수 있는 이름을 짓는다는건 생각보다 연습이 많이 필요한 것 같습니다
- Show warning toast msg if name or phone_num is Empty. - Show success toast msg if both name and phone_num is not Empty.
- Show cancled toast msg
- Modified AndroidManifest.xml to add 'adnroid:windowSoftInputMode="adjustResize"'. - Ensured bottom_view remains visible if soft_keyboard is diplayed
- Add edittext_width and edittext_height to dimens.xml - Add [attr]_hint to strings.xml - Update EditText layout in activity_main.xml to use resource values for width, height, hint
- MainActivity : Display the list of added contacts - ViewContact : Show the detailed info of the selected contact - ResiterContact : Register new contact
… RecyclerView, and Button
- Use a rounded view with black border - Add Textview to display the first letter of the name in a Circular_background
lateinit var recyclerView: RecyclerView | ||
lateinit var viewAdapter: PersonAdapter | ||
lateinit var viewManager: RecyclerView.LayoutManager | ||
lateinit var emptyTextview: TextView |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
startActivity(intent) | ||
} | ||
|
||
recyclerView = findViewById<RecyclerView>(R.id.recyclerView).apply { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
apply scope function을 의도대로 잘 작성해주셨네요! 👍
lateinit var viewAdapter: PersonAdapter | ||
lateinit var viewManager: RecyclerView.LayoutManager | ||
lateinit var emptyTextview: TextView | ||
var personList: MutableList<Person> = mutableListOf<Person>() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
personList의 책임 주체가 어디인지 분명히 하는게 좋을 것 같네요. 이는 멘티분이 생각하시는 대로 일관성있게 작성하시는게 중요합니다.
Android MVC 패턴에서 SSOT (Single Source of Truth)를 챙기기에는 현재 단계에서는 생각할 부분이 많고 모호한 부분이 존재한다고 생각합니다. 현재 작성해주신 코드에서는 SSOT가 MainActivity일 수도 PersonAdapter일 수도 있겠네요. 누가 책임을 가질지는 모호할 수 있지만 중요한 것은 두 객체간의 공유하는 데이터가 있을 때 이를 변경하는 것은 하나의 클래스에서 해야만 한다는 것입니다.
지금 작성해주신바로는 Adapter, Activity 모두 PersonList에 접근해서 데이터를 변경할 수 있네요.
이를 해결하기 위해서 두 가지 방법으로 리팩토링 할 수 있습니다.
-
MainActivity가 데이터를 관리하게 한다고 한다면 Adapter를 최대한 멍청하게 만드셔야 합니다. 지금과 같은 방식으로 데이터의 변경에 대한 부분을 Adapter를 사용하는 쪽에서 책임을 지는것 입니다. (데이터를 추가하고, 데이터의 변경이 있음을 알리는 등) 이 방법의 경우 장점은 Adapter를 최대한 멍청하게 유지함으로써 다른 View에서도 사용하기 편리할 수 있습니다. 하지만 단점은 데이터 추가 및 변경을 사용하는 쪽에서 하나하나 다 알려줘야 하기 때문에 사용하는 곳(MainActivity 등 View)의 역할이 더더욱 커질 수 있겠네요.
-
Adapter가 데이터를 관리하는 방식입니다. Adapter가 데이터를 관리해서 MainActivity는 단순히 Adapter에 초기 데이터를 넘겨주고 데이터의 추가 및 수정, 변경 감지에 대한 책임을 Adapter로 미뤄버리는 것입니다. 이 방식의 장점은 MVC 패턴의 가장 큰 단점인 Activity가 너무 많은 역할을 하는 상태(God Object)를 완화시킬 수 있겠네요. 하지만 이 방식도 단점이 존재합니다. 바로 해당 Adapter를 쓰는 View와 강결합된다는 것입니다.
사실 이 문제는 지금 안드로이드를 시작하는 단계에서 생각하기에는 무거운 주제일 수 있습니다. 앞으로 안드로이드를 공부하시다보면 여러가지 아키텍처에 대해서 배우실 겁니다. 현재 단계에서 존재하는 이러한 단점을 인지하고 있으면 추후 다른 아키텍처나 또 다른 Adapter 들을 배우실 때 도움이 되실 거에요. 두 가지 방식 중 한 가지 방식으로 리팩토링을 진행해 보셔도 좋고 힘드시다면 단순히 생각만 해보셔도 좋을 것 같습니다 ~
val intent = Intent(this, ViewContact::class.java).apply { | ||
putExtra("name", it.name) | ||
putExtra("tel", it.tel) | ||
putExtra("mail", it.mail) | ||
putExtra("sex", it.sex) | ||
putExtra("memo", it.memo) | ||
putExtra("birth", it.birth) | ||
} | ||
startActivity(intent) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 방식은 Adapter가 가지는 데이터를 신뢰한다는 생각이 깔려있네요. 이런 부분에서 데이터 일관성이 깨질 수 있습니다. 만일 데이터 주체가 MainActivity에 있다면 단편적인 정보(index 등)을 가지고 MainActivity에서 조회하는 방법을 사용할 수 있겠네요.
updateUI() | ||
} | ||
|
||
private fun updateUI() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updateUI는 데이터가 변경이 될 때마다 이뤄져야 하는 것으로 보입니다. Observable 패턴을 쓰지 않고는 이러한 변경을 감지하는게 힘들 수 있겠네요. 이를 위해 adapter에서 데이터 감지를 포착해주는 콜백 메서드가 있습니다. 이를 활용해보세요.
personList.add(Person(name, tel, mail, sex, memo, birth)) | ||
viewAdapter.notifyDataSetChanged() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MainActivity에서 데이터를 관리한 다면 이 두 메서드는 묶어서 하나의 메서드로 작성할 수 있겠네요.
personList.add(Person(name, tel, mail, sex, memo, birth)) | ||
viewAdapter.notifyDataSetChanged() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
notifyDataSetChanged()를 사용하시면 IDE에서 주의사항을 알려줄 텐데 이 메서드는 효율적인 방법이 아닙니다. 한 번 찾아보시겠어요?
android:layout_width="60dp" | ||
android:layout_height="60dp" | ||
android:layout_gravity="bottom|end" | ||
android:layout_margin="16dp" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
end 및 bottom 쪽으로만 margin이 필요한데 전체 margin을 주신 이유가 있을까요?
} | ||
|
||
recyclerView = findViewById<RecyclerView>(R.id.recyclerView).apply { | ||
setHasFixedSize(true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
성능을 위한 코드를 잘 작성해 주셨네요.
혹시 이 함수가 어떤 역할을 하는지 알고 계신가요?
val name = data?.getStringExtra("name") ?: "" | ||
val tel = data?.getStringExtra("tel") ?: "" | ||
val mail = data?.getStringExtra("mail") ?: "" | ||
val sex = data?.getStringExtra("sex") ?: "" | ||
val memo = data?.getStringExtra("memo") ?: "" | ||
val birth = data?.getStringExtra("birth") ?: "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 정보들이 null일 때 꼭 빈 String을 가져야 하나요? 그냥 null을 쓰면 안될까요?
안녕하세요 앞으로 6주간 코드 리뷰를 도와드리게 된 제리 멘토라고 합니다. |