[Android Studio] DiaryApp 구조
맨땅에 헤딩으로 시작해서 어떻게 필수라고 생각되는 기능 중 일부들을 구현하는데 성공했다.
가끔은 에러때문에 며칠을 삽질하는 돌아가고 싶지 않은 여러 시행착오를 거치기도 했는데 아무래도 경험 부족이
가장 큰 원인이 아닌가 싶어 같은 실수를 반복하지 말자는 의미에서 기록해두기로 했다.
첫 번째는 만들어보고자 했던 ‘DiaryApp’의 개발 동기 및 코드들이 어떤 구조로 짜여있는지 써보려 하며
두 번째는 구현하는 과정에서 겪었던 오류를 간결하게 적어보려고 한다.
DiaryApp 개발 동기
스마트폰을 키고 유용하게 가장 많이 활용하는 앱이 네이버 캘린더였다.
똑같이는 만들지 못해도 비슷한 기능 정도는 구현해보자는 생각에 시작을 했고
초반 계획에는 캘린더도 추가하고 일별로 스케쥴을 관리할 수 있도록 (네이버 캘린더처럼)
이벤트를 추가/삭제하는 기능을 만들고 싶었으나 캘린더에서 일자별로 이벤트를 저장하는 방법을
내 기준에 이해할 수 있는 가이드를 찾지 못해서(..) 이 부분은 구현을 포기하고 메모 기능만 추가했다.
나중에 도움되는 정보를 얻게되면 확장하는 것도 적극적으로 고려해볼 예정이다.
DiaryApp 구조
모든 영/한 폰트는 네이버 마루부리 폰트를 사용했다. 다운로드는 여기에서 할 수 있다.
적용은 봉캔두님의 글을 참고했다.
먼저 스플래시 화면, 로그인 그리고 회원가입 화면이다.
스플래시 화면을 사용하는 원래 목적도 있겠지만 기본적으로 다들 만들길래 추가했다.
로그인, 회원가입은 서버와 통신하면서 동작하도록 구현했다. (서버는 Django REST Framework로 만듦)
로그인, 회원가입 모두 POST로 처리하도록 했고 DELETE는 구현하지 않았다. (Insomnia로 테스트시 원활히 작동)
이에 관련된 자세한 내용은 이 글을 참고.
다음은 메모를 저장/수정/삭제할 수 있는 기능을 구현했다.
Simplified Coding 영상들을 참고했다. 생각보다 코틀린 컨텐츠가 많지 않았다😢
데이터들은 Android Room을 통해서 저장하도록 처리했다. 방법은 Room 외에도 SQL, Firebase 등이 있었는데
내가 잘 찾지 못한 것도 있겠지만 좀 따라해보려 하면 에러가 심해서 최종적으로 위 영상을 따라갔다.
차례대로 메인화면, 작성 기본 화면, 작성 후 화면이다.
그리고 작성시 일어날 수 있는 케이스별로 예외 처리해줬다.
차례대로 날짜가 형식에 맞지 않을 때, 제목이 비거나 22자가 넘을 때, 내용이 비었을 때이다.
한글 기준으로 2줄이 넘어가지 않게끔 처리하기 위해 제목 상한을 22자로 설정했다. 큰 의미는 없다.
메모 목록에서 특정 메뉴를 누르면 수정 화면으로 돌아가고 이 때 삭제할 수 있는 버튼이 활성화되도록 했다.
앱은 항상 엑티비티에서 엑티비티로의 이동으로만 처리하면 되는줄 알았는데 강의에서 fragment를 다뤄서 써보게 됐다.
바로 메모 추가 버튼을 눌렀을 때 fragment를 띄우게 되는데, CalenderActivity.kt
에서
val navController = Navigation.findNavController(this, R.id.fragment)
NavigationUI.setupActionBarWithNavController(this, navController)
onCreate() 안에 있는 이 두 줄이 바로 그 역할을 한다. (HomeFragment.kt
로 이동)
참고로 onSupportNavigateUp()
가 오버라이딩 돼있는데 뒤로가기 기능을 활성화한 것이다.
HomeFragment
에서는 launch{}
에서 RecylcerView를 활용해 메모 목록을 표시한다.
그리고 메모 목록들은 NotesAdapter.kt
의 내용대로 동작하게 된다.
holder.binding.textDate.text = notes[position].last_modified_at
holder.binding.textViewTitle.text = notes[position].title
이 부분이 날짜와 제목을 출력하도록 하고,
바로 밑에 holder.binding.root.setOnClickListener{}
는 이미 있는 메모를 클릭했을 때
수정 화면(AddNoteFragmet)으로 이동하도록 한다. (direction에 대해서는 nav_graph.xml
참고)
HomeFragment
에서 Fragment
가 아닌 BaseFragment
를 상속받은 이유는 영상에 따르면
Coroutines을 사용하기 위함이라고 한다. 비동기적인 실행을 아주 쉽게 하기 위함이라고 하는데
찾아보니 Android 공식 문서에도 똑같이 쓰여있었다.
일단 두드러지게 보이는 장점은 성능 향상인 것 같은데 규모가 작아서 차이점은 잘 모르겠다. 트렌드인듯 하다.
발생했던 에러 및 해결 방법
- lateinit property binding has not been initialized (+ 추가 버튼(in HomeFragment) 작동X)
ViewBinding이 문제였다.
Activity에서는 다음 내용들을 추가해주면 됐었다.
클래스 초반부에 private lateinit var binding: MainAcitvityBinding,
근데 Fragment의 경우 onCreate()이 없고 onCreateView()가 있었다.
그냥 이게 이거겠거니 싶어서 2번째 줄에 있는 코드를 넣었는데 이 부분이 원인이었다.
binding = FragmentHomeBinding.inflate(inflater), return binding.root
로 고쳐야 한다.
Adapter에서도 같은 오류가 났는데 여기서도 다르게 처리해줘야 한다. stackoverflow에서 해결했다.
관련 내용은 Android 공식 문서에 친절히 설명돼있다.
-
Adapter에서 ViewBinding과 관련된 오류를 수정했었지만 버튼이 여전히 작동X
NoteViewHolder에서 RecyclerView.ViewHolder의 인자를 binding.root로 쓰면 위와 같은 문제가,
view
를 쓰면 각 파일의 preview가 보이지 않는 현상이 있었는데holder.view.setOnClickListener
를
holder.binding.root.setOnClickListener
로 바꾸니 해결됐다. stackoverflow에 질문을 올려 도움을 받았다.
Android Room Tutorial 영상을 유튜브에서 참고하고 따라가다보니 각 기능들이 어떻게 유기적으로 연결되는지를
파악하지 못해서 발생한 문제로 보인다.
- 메모 목록을 한 줄에 하나씩 표시(RecyclerView를 ListView처럼 쓰기)가 안됨
영상을 따라 코드를 쳤는데 자세히 설명해주지 않아서 원인을 찾는데까지 힘들었다.
RecyclerView를 쓰기는 하는데 메모 항목들을 가로 정렬하겠다는 코드다.
이 코드의 정체가 뭔지 몰라서 영향 안주겠거니 하고 계속 xml을 뜯어 고쳐대도 영향이 없어서
3일동안 고생했다. stackoveflow에서 도움을 받았다.
Staggerd Grid가 뭔질 알았다면 금방 눈에 들어왔을텐데 몇 번 검토를 하는 내내 이걸 못읽었다니 좀 허망하다.
- DB 구조 변경 후 기존 데이터와의 충돌
Looks like you've changed schema but forgot to uplast_modified_at the version number. You can simply fix this by increasing the version number.
라는 오류가 떴는데, 검색해보니 내용대로 버전을 업데이트하는 방법도 있지만 앱을 재설치하는 방법도 있다고 한다.
물론 Room을 이용했기 때문에 재설치를 하면 저장된 파일들은 모두 사라지게 된다. 그냥 재설치해서 해결했다.
관련 내용은 여기를 참고.
만약 이미 앱을 서비스하는 중이었고 사용자층이 어느 정도 있는 상태에서 이런 일이 일어난다면
어떻게 대처해야할지 조금 생각해보게 되는 상황이었다.
-
폰트 추가 후
Duplicate resources
에러 발생
겹치는게 있다는 말인데, 글꼴을 넣는 과정에서 파일 이름이 A라면 A.otf, A.ttf를 한 디렉토리에 넣었었다.
실제로 앱 전반에 폰트를 적용하면서 A라는 이름만 사용했을 뿐 확장자를 기입하지 않아서 에러를 뱉은걸로 보인다.
하나를 지우니 간단히 해결됐다!
- 레이아웃이 ActionBar 및 상단바와 겹치는 현상
xml에서 Layout 설정란에android:fitsSystemWindows="true"
을 추가하니 해결됐다.
의도한 대로 완성하진 못해 결과물은 허술하지만 여러 에러들을 거치고 디버깅하는 과정에서 배운 점이 많았다.
아무래도 첫 개발 경험이었기에 좀처럼 고치기 힘든 에러를 만나면 하루는 꼬박 보내는 경우가 많았는데
구글링해서 해결이 안되면 stackoverflow에 적극적으로 헬프를 외치면서 익힌 여러 해결책들이 값진 경험이 됐고
후에 있을 프로젝트에서 소소한 역할을 하지 않을까 싶다. 코틀린 문법도 잘 모르는 상태여서 많이 힘들었다😂
가이드가 없었다면 꿈에도 몰랐던 메소드들이 이번 기회로 한 걸음 다가온 것 같아서 의미있는 경험이 됐다!
댓글남기기