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_이지은 1주차 과제 #33

Open
wants to merge 13 commits into
base: jieunyume
Choose a base branch
from

Conversation

JieunYume
Copy link

@JieunYume JieunYume commented Jun 28, 2024

📞기능 목록

step1

  • 연락처 정보 입력하기
    • 이름: 필수-Toast 메세지(이름을 입력해주세요.)
    • 전화번호
      • 필수-Toast 메세지(전화번호를 입력해주세요.)
      • 숫자만 가능-Toast 메세지(전화번호는 숫자로만 입력해주세요.)
    • 메일
    • 더보기
      • 클릭하면 입력 폼이 확장된다.
        • 생일: 캘린더
        • 성별: 여자, 남자 중에 선택한다.
        • 메모
  • 저장하기
    • Toast(저장이 완료되었습니다.)
  • 취소하기
    • Toast(취소되었습니다.)

step2

  • 연락처 목록
    • 이름 앞글자가 적힌 사진과 이름 정보가 나타난다.
    • 스크롤이 가능하다.
  • 연락처 추가
    • 추가 도중 취소하면 확인 팝업이 나타난다.
    • 추가가 완료되면 Toast(저장이 완료되었습니다.)
  • 연락처 상세 보기
    • 이름과 전화번호 정보가 나타난다.

📞어려웠던 점

  • 시간이 촉박해서 Serializable이나 let 문법 등의 개념을 깊게 이해하지 못하고 코드를 작성했던 것이 아쉬웠습니다.

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

  • 과제를 다 끝내고 보니 저의 commit 메세지가 일관성이 없는 것 같다는 생각이 듭니다. xml 디자인 작업과 kotlin 기능 작업을 구분하지 않고 commit 메세지를 작성했는데, 구분해서 커밋하는 것이 좋을까요? 그리고 어떤 작업을 했는지 명확하게 알 수 있게 하려면 커밋 메세지를 어떤 식으로 작성하는 것이 좋을지 코치님만의 좋은 공식이 있을까요? 커밋 메세지에 대한 피드백 부탁드립니다!
  • 이전 미니 과제에서는 함수 분리를 어떻게 해야할지 감이 왔었는데, 안드로이드 프로젝트에서는 잘 모르겠습니다.

@JieunYume JieunYume changed the title 1주차 과제 부산대 Android_이지은 1주차 과제 Jun 28, 2024
@bigstark bigstark self-requested a review July 1, 2024 13:25
Copy link

@bigstark bigstark left a comment

Choose a reason for hiding this comment

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

안녕하세요 지은님! 앞으로 함께할 강대규 멘토입니다.
앞으로 6주동안 잘 부탁드려요 :)

고생 정말 많으셨습니다. 코드에 노력의 흔적이 엿보입니다.


과제를 다 끝내고 보니 저의 commit 메세지가 일관성이 없는 것 같다는 생각이 듭니다. xml 디자인 작업과 kotlin 기능 작업을 구분하지 않고 commit 메세지를 작성했는데, 구분해서 커밋하는 것이 좋을까요? 그리고 어떤 작업을 했는지 명확하게 알 수 있게 하려면 커밋 메세지를 어떤 식으로 작성하는 것이 좋을지 코치님만의 좋은 공식이 있을까요? 커밋 메세지에 대한 피드백 부탁드립니다!

커밋 메시지는 기능 단위로 잘 쪼개신 것 같아요. 커밋을 잘 쪼갤 수 있다는 것은 개발을 할 때 설계를 미리 하고, 그에 따른 세분화된 일정을 산출하는 것과 같아요. 결국 경험이 가장 필요로 되는 항목인 것 같습니다. 그럼에도 불구하고 기능단위로 잘 쪼개주셨어요. xml 단위와 kotlin 기능 단위는 크게 중요하지는 않아요. 커밋의 사이즈가 너무 크지만 않다면 (20 file changes 넘는다든가 등...) 괜챃습니다. 다른 분들의 코드 리뷰를 한번 모의로 진행해보세요. 혹은 라이브러리의 커밋을 관찰해보세요. 기능단위를 확인해볼 수 있을겁니다.

이전 미니 과제에서는 함수 분리를 어떻게 해야할지 감이 왔었는데, 안드로이드 프로젝트에서는 잘 모르겠습니다.

최대한 쪼갠다고 생각하면 조금 더 수월할 거에요.

Comment on lines +20 to +33
val name_input: EditText = findViewById(R.id.name_input)
val phone_number_input: EditText = findViewById(R.id.phone_number_input)
val email_input: EditText = findViewById(R.id.email_input)

val birth_date_input: EditText = findViewById(R.id.birth_date_input)
val birth_date_radiogroup: RadioGroup = findViewById(R.id.birth_date_radiogroup)

val gender_input: EditText = findViewById(R.id.gender_input)
val memo_input: EditText = findViewById(R.id.memo_input)

val save_button: Button = findViewById(R.id.save_button)
val cancel_button: Button = findViewById(R.id.cancel_button)
val see_more_button: LinearLayoutCompat = findViewById(R.id.see_more_button)
val see_more_input_form: LinearLayoutCompat = findViewById(R.id.see_more_input_form)
Copy link

Choose a reason for hiding this comment

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

기본적으로 코틀린은 Kotlin coding convention 을 따르게 됩니다.
코딩 컨벤션을 따르게 된다면 다른 리뷰어가 지은님의 코드를 보게될 때 비교적 쉽게 코드를 읽게 도와줍니다.
(https://velog.io/@productuidev/coding-conventionstyle-guide)

Copy link

Choose a reason for hiding this comment

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

또한 ViewBinding 이라는 것이 있어요.
findViewById 의 번거로움을 획기적으로 줄여줄 뿐더러, null safety, type safety 하다는 장점을 가지기도 합니다.

ViewBInding 을 사용하신다면 조금 더 코드작성이 수월해질 것으로 예상됩니다.

val see_more_button: LinearLayoutCompat = findViewById(R.id.see_more_button)
val see_more_input_form: LinearLayoutCompat = findViewById(R.id.see_more_input_form)

see_more_input_form.visibility = View.GONE
Copy link

Choose a reason for hiding this comment

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

View 의 extension 함수 중 isVisible 이라는 놈이 존재합니다.

이것을 사용한다면 아래처럼 조금 더 간편하게 visibility 를 컨트롤할 수 있을 것입니다.

seeMoreInputForm.isVisible = false 

Comment on lines +51 to +57
this.let { it1 ->
DatePickerDialog(it1, { _, year, month, day ->
run {
birth_date_input.setText(year.toString() + "." + (month + 1).toString() + "." + day.toString())
}
}, year, month, day)
}?.show()
Copy link

Choose a reason for hiding this comment

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

여기서의 let 은 사용하지 않는 것이 좋을 것 같아요. apply, let, run, also, with 등을 범위 지정 함수라고 하는데, 코틀린 코드에 익숙해지기 전까지는 사용하지 않는 것이 조금 더 성장에 도움이 될 것 같아요.

만약 사용하고 싶다면, 도움이 되는 레퍼런스 공유드려요.
(https://kotlinworld.com/255)

Comment on lines +70 to +92
if (name_input.text.isNullOrEmpty()) {
Toast.makeText(this, "이름을 입력해주세요.", Toast.LENGTH_SHORT).show()
}
else if (phone_number_input.text.isNullOrEmpty()) {
Toast.makeText(this, "전화번호를 입력해주세요.", Toast.LENGTH_SHORT).show()
} else if (!phone_number_input.text.all { Character.isDigit(it) }){
Toast.makeText(this, "전화번호는 숫자로만 입력해주세요.", Toast.LENGTH_SHORT).show()
}
else{
Toast.makeText(this, "저장이 완료되었습니다.", Toast.LENGTH_SHORT).show()
val contact: Contact = Contact(
name_input.text.toString(),
phone_number_input.text.toString(),
email_input.text.toString(),
birth_date_input.text.toString(),
gender_input.text.toString(),
memo_input.text.toString()
)
val intent: Intent = Intent()
intent.putExtra("contactInfo", contact)
setResult(RESULT_OK, intent)
finish()
}
Copy link

Choose a reason for hiding this comment

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

이렇게 if 문이 반복해서 나올 경우에는 when 절으로 처리하는 것이 조금 더 명확합니다.

when {
  name_input.text.isNullOrEmpty() -> {   
    Toast.makeText(this, "이름을 입력해주세요.", Toast.LENGTH_SHORT).show()
  }
  phone_number_input.text.isNullOrEmpty() -> {
    Toast.makeText(this, "전화번호를 입력해주세요.", Toast.LENGTH_SHORT).show()
  }
  !phone_number_input.text.all { Character.isDigit(it) } -> {
    Toast.makeText(this, "전화번호는 숫자로만 입력해주세요.", Toast.LENGTH_SHORT).show()
  }
  else -> {
    // do else things...
  }
}

Copy link

Choose a reason for hiding this comment

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

또한 각 when 절에서 직접 수식값을 사용하기보다, 명확한 boolean 형태의 값을 지역변수로 선언하여 사용하면 리뷰어가 리뷰하기 조금 더 수월해집니다. 추후 코드 관리 측면에서도 이해하기 편하구요.

val isNameEmpty = name_input.text.isNullOrEmpty()
val isPhoneNumberEmpty = phone_number_input.text.isNullOrEmpty()
val isPhoneNumberNotDigits = !phone_number_input.text.all { Character.isDigit(it) }

when {
  isNameEmpty-> {   
    Toast.makeText(this, "이름을 입력해주세요.", Toast.LENGTH_SHORT).show()
  }
  isPhoneNumberEmpty-> {
    Toast.makeText(this, "전화번호를 입력해주세요.", Toast.LENGTH_SHORT).show()
  }
  isPhoneNumberNotDigits -> {
    Toast.makeText(this, "전화번호는 숫자로만 입력해주세요.", Toast.LENGTH_SHORT).show()
  }
  else -> {
    // do else things...
  }
}

super.onCreate(savedInstanceState)
setContentView(R.layout.activity_contact_detail)

val contact = intent.getSerializableExtra("contactDetail") as Contact
Copy link

Choose a reason for hiding this comment

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

이부분 또한 아쉬웠어요. Contact 정보가 필요하다면, Contact 를 Parcelable 하게 만드는 것이 조금 더 좋아보입니다.

또한 kotlin-parcelize 를 사용한다면 조금 더 Contact 를 parcelable 하게 만들 수 있습니다.

Copy link

Choose a reason for hiding this comment

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

만약 parcelable 을 쓰지 않더라도, contact 내부의 값을 모두 따로따로 String 으로 주고받아도 좋을 것 같아요. 예를들어,

val name = intent.getStringExtra("name")
val phoneNumber = intent.getStringExtra("phoneNumber")
val email = intent.getStringExtra("email")
// 이하 생략

val contact = Context(
  name = name,
  phoneNumber = phoneNumber,
  email = email,
 // 이하 생략
)

1 -> {
when(resultCode){
AppCompatActivity.RESULT_OK -> {
val contact: Contact? = data?.getSerializableExtra("contactInfo") as Contact?
Copy link

Choose a reason for hiding this comment

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

오호 흥미로운 주제네요. kotlin 의 safe cast 와 nullable cast 의 충돌인데, 한번 해당 링크 확인해보면 좋을 것 같네요 :)

private val activity: ContactListActivity
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

inner class ViewHolder(val itemView: View) : RecyclerView.ViewHolder(itemView) {
Copy link

Choose a reason for hiding this comment

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

요거 굳이 inner class 로 사용하는 이유가 있을까요?

class ContactRecyclerAdapter(
private val contactList: MutableList<Contact>,
private val inflater: LayoutInflater,
private val activity: ContactListActivity
Copy link

Choose a reason for hiding this comment

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

activity 를 변수로 넘기는 것은 금기시해야할 것 중 하나입니다. inflater 또한 파라미터로 받을 필요는 없을 것 같구요.
아이템을 클릭했을 때 이동해야한다면, 아이템이 클릭되었음을 알려주는 listener 를 정의하고 그것을 파라미터로 받는 것이 좋습니다.

interface OnContactClickListener {
    fun onContactClicked(position: Int)
}

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

Successfully merging this pull request may close these issues.

2 participants