안드로이드 앱 개발 포트폴리오 | 여행 가계부 서비스

내일배움캠프 7기 앱 개발 과정 안드로이드 트랙 수료생 최종 프로젝트 '트립메이트'를 소개합니다.
Mar 07, 2024
안드로이드 앱 개발 포트폴리오 | 여행 가계부 서비스
notion image
💡
TripMate는 아래와같은 Needs에서 시작되었습니다!
1️⃣ 여러사람과의 여행에서의 수입지출을 깔끔하게 기록하고싶다.
2️⃣여행갈때 네이버블로그를 많이 찾아보게되는데 내가 원하는 정보만 스크랩해놓고 한군데서 보고싶다.

⚙️ 아키텍쳐

notion image
notion image

주요 기능

각 여행일정별 가계부를 만들어 기록&관리

  • 각 여행일정별 가계부를 만들어 관리가 가능합니다.
  • 각 가계부별 통계기능을 제공하여 어떤 카테고리에 얼마나 지출하였는지 한눈에 파악이 가능합니다.
  • 정산하기 기능을 통하여 여행에 참여한 사람들의 1인당 지출액을 알 수 있으며 공유하기 기능을 통해 공유할수있습니다.
notion image
notion image

커뮤니티 게시글 작성 및 여행계획 공유

  • 커뮤니티에 자유롭게 글을 작성할 수 있습니다.
  • 커뮤니티에는 내가 다녀온 여행후기나 정보등을 공유할 수 있습니다. 또한 내가 이전에 공유했던 가계부 통계역시 업로드 가능합니다.
notion image

좋아요

  • 커뮤니티의 게시글 중 맘에 드는 게시글에 좋아요를 할 수 있습니다.
  • 좋아요를 많이 받은 게시글은 홈 화면의 인기글에서 상위목록으로 업데이트 됩니다.
    • notion image

커뮤니티 검색

  • 커뮤니티 게시판의 글을 검색할 수 있습니다.
notion image

커뮤니티 글 스크랩

  • 커뮤니티 글 중 원하는 항목을 스크랩하여 내 정보에서 볼 수 있습니다.
  • 스크랩한 항목은 언제든지 스크랩목록에서 삭제가능합니다.
notion image

네이버 블로그검색

  • 네이버 블로그 API를 활용하여 검색하고 블로그를 볼 수 있습니다.
  • 검색창에 아무 단어도 검색하지않은상태일경우 추천검색어를 화면에 표시합니다.
  • 블로그를 보던 중 다른 광고글등을 클릭했을경우 이동하지않고 현재 블로그페이지에 머무를 수 있도록합니다.
notion image

블로그 스크랩

  • 선택한 블로그글을 스크랩합니다.
  • 내가 스크랩한 블로그 글은 검색결과에도 동일하게 반영되어 표시됩니다. 따라서 직접 블로그 글을 들어가서 확인하지않아도 검색단계에서 내가 스크랩한 블로그글의 목록이 표시됩니다.
notion image

🔍 기술적 의사결정

Firebase
  • Realtime Database :
    • 무료로 사용가능하면서 서버구축없이 즉시 게시판, 로그인정보등을 저장하고 불러 올 수 있었기때문입니다.
    • 러닝커브가 낮습니다.(공식문서가 잘 되어있음)
    • 사용자가 많습니다.(Reference가 많습니다)
  • Auth
    • 구글로그인을 안드로이드에서 빠르게 구현할 수 있어서입니다.
    • 러닝커브가 낮습니다.(공식문서가 잘 되어있음)
    • 사용자가 많습니다.(Reference가 많습니다)
Naver 블로그 검색 API
  • 저희 앱이 주 타겟팅은 대한민국을 여행하는 사람입니다. 한국인들이 여행에서 가장 많이 참고하는 글이 네이버 블로그이기때문에 선택했습니다.
  • 여러곳을 비교해보았으나 아래와같은 이유로 채택을 거부하였습니다.
    • 다음 검색: 네이버 검색에비해 경쟁력이 떨어짐. 조원들과 이야기나누었을때 주변의 많은 사람들이 그리고 본인이 여행때 가장많이 참고하는것은 네이버 블로그 글이었다고 하였음.
    • 구글 Place API: 음식점 정보와 별점등을 받아 사용할 수 있지만 무료로 받을 수 있는 정보가 상당히 제한되어있는점. 한국에서는 구글지도보다 네이버지도를 더 선호하는 점 등이 있습니다.
Room
  • 가계부를 구현할때 로컬 DB를 상정하고 기획하였습니다. 안드로이드에 Room 이외에도 다른 DB 라이브러리들이 존재하는것으로 알고있지만 Room을 선택한 이유는 다음과 같습니다.
    • 안드로이드에서 공식 지원하는 ORM
    • Reference가 많이 있습니다.
Recyclerview + ListAdapter(DiffUtil)
  • 스크롤이 가능하며, 다수의 데이터를 효율적으로 관리해줄수있는 기술이 필요한데 RecyclerView는 ViewHolder를 사용하여 화면에 보이는 item의 데이터를 불러와 View에 표시해 주고 화면에 보이지 않는 item들은 데이터를 가져오지않아 리소스를 절약해줍니다.
  • ListAdapter를 사용한 이유는 Adapter의 코드량이 줄고, DiffUtil을 통해 갱신할때 새롭게 list를 Adapter로 넘겨주게되면 DiffUtil에서 이전 list와 새로운 list의 item을 비교하여 다를경우에만 item을 교체해주는 방식이기때문에 효율적으로 관리할 수 있다는 장점이 있습니다.
TabLayout + ViewPager2
  • 여러 옵션이 있었지만 BottomNavigation을 구현하는데 조원 모두 기술적으로 익숙하고 이해도가 있는 TabLayout과 ViewPager2 조합을 선택했습니다.
ViewModel + LiveData + Flow
  • ViewModel의 경우 실제 UI를 그리는 영역과 비지니스 로직을 분리하여 Activity(Fragment)에 과중한 책임을 분산시켜 확장성 높고 유지보수가 가능한 코드를 만들고자 사용하게되었습니다.
  • 마찬가지로 LifeCycle을 고려해서 설계된 LiveData는 데이터를 실시간으로 업데이트하여 View에 알려주는 기능을하기에 사용하게되었습니다.
  • Flow는 연속적인 데이터를 받기위해 디자인된 기술로 사용이유는 MVVM의 구조상 RemoteDataSource에서 LiveData를 사용할 수가 없기에 Flow를 사용하여 데이터를 처리하게되었습니다.
Coil
  • 이미지 로드 라이브러리로 Glide를 초반에 사용하였었는데 Glide보다 더 간편한 사용방식과 다른 라이브러리에비해 가볍다는 자료를 보게되어 팀원들과 함께 논의 후 바꾸게되었습니다.

📌 트러블 슈팅

ListAdapter 갱신 이슈
  • 문제
    • user 상세 페이지에서 좋아요를 눌러도 갱신이 되지 않고, 게시글을 클릭했을때 조회수가 갱신되지 않는 문제가 있습니다.
  • 해결
    • 조회 수가 RDB에 저장돼있고, 받아오고 있고, 데이터의 변화를 감지도 정상적으로 작동되는 것을 확인했으며 이는 갱신 문제인것으로 판단함. notifyDataSetChanged()를 사용하니 정상적으로 갱신되지만 ListAdapter를 사용하고 있음에도 갱신이 안 되는 것에 의문을 가짐.
    • 어댑터를 확인해 보니 areContentsTheSame에서 item의 key 값을 서로 비교하고 있는데, 정작 데이터의 변화는 key가 아니라 조회 수, 좋아요 부분이 변화되기 때문에 감지를 할 수 없어서 화면이 갱신이 되지 않았습니다.
    • 고유한 key 값을 이용해서 아이템을 비교하는 건 맞지만 해당 값이 변하지 않으면 갱신되지 않는 것을 알 수 있었습니다.
    • Fragment에서 notifyDataSetChanged()를 제거하고, Adapter의 내용 비교에서 아이템을 비교했더니 areContentsTheSame에서 변경을 감지하고 false를 반환해서 정상적으로 화면이 갱신되는 것을 확인할 수 있었습니다
두 종류의 라이브데이터 통합 이슈
  • 문제
    • 데이터 클래스를 통합하기 위해 공용 인터페이스를 생성하고, 각각의 데이터 클래스에 인터페이스 반환 타입을 추가 하는 방식을 선택 했으며, ViewModel에서 데이터는 통합돼서 정상적으로 로그에 찍히나 MyPage 화면에서 데이터가 갱신이 되지 않는 이슈가 발생했습니다.
  • 해결
    • 통합이 된 라이브데이터를 관찰하는 프래그먼트에서 블로그 북마크 데이터와 게시판 북마크 데이터를 불러오기 전에 통합을 수행하고 있기 때문에 빈 값으로 호출되는 것을 확인했습니다 결론적으로 블로그 데이터와 RDB 게시판 데이터를 불러오기도 전에 합치고 있으니 문제가 있는 것을 알 수 있었습니다. 북마크 된 블로그 데이터와 RDB 게시판을 불러오는 라이브데이터를 각각 관찰하고 데이터를 불러올 때마다 라이브데이터를 통합하는 함수를 호출시켜서 해결했습니다

👥 팀원 소개

담당
이름
Github
팀장
서정한
부팀장
박성수
팀원
김성환
팀원
황일규
팀원
윤동현

📁프로젝트 깃허브 & 서비스 주소

프로젝트 깃허브
서비스 주소
 
Share article
Subscribe to our newsletter
RSSPowered by inblog