본문 바로가기

안드로이드 Android

안드로이드 개발 (4) FireStore 채팅 목록 만들기

https://gift123.tistory.com/26

 

안드로이드 개발 (3) - FireBase 게시판 댓글

Loner 입니다. 주말이 가까워지면 항상 사이드 협업 프로젝트를 진행합니다. 평일은 메인 외주프로젝트를 진행하고 있습니다. 마음 같아서는 메인 프로젝트 관련해 포스팅을 하고 싶지만, 가능하

gift123.tistory.com

이전편에서 언급했었다 시피 주말에 사이드 프로젝트를 하고 평일에는 메인 프로젝트를 따로 진행하고 있습니다.

(지금보니 일터도 안드로이드 취미도 안드로이드로 살고 있었다.)

금요일 저녁 되서 사이드 프로젝트에 대한 추가 작업을 하고 있는데 이 포스팅은 그 흔적에 대한 정리입니다.

 

FireBase 게시판 댓글을 작업 한 후 나는 A팀 작업에서 B팀 작업으로 넘어갔습니다.

A팀은 FIreBase RealTimeDatabase를 사용하고 있었고 B팀은 FireBase FireStore를 사용중 입니다. 

둘의 공통점은 똑같은 noSql 입니다.

차이점은 RealTimedatabase는 db구조가 단순하고 쿼리는 투박하며 json형식으로 추출해서 데이터를 이전하기 쉽습니다.

FireStore는 쿼리검색을 정교하게 할 수 있으며, 콜렉션,도큐먼트,데이타 3가지 구조로 나뉘는 db구조 형식을 뛰고있습니다. 더 depth 깊게 사용이 가능합니다.

 

이야기가 길었군요 아무튼 오늘 작업한 내용을 가지고 채팅목록 만드는법에 대해 설명하도록 하겠습니다.

이미 채팅 목록을 구현했었지만 이슈가 발생해 다시 해결 한 후의 상황을 기준으로 정리하겠습니다.

 

채팅방 리스트 만들기 

언어:Kotlin

- ViewBinding 사용 

 

B프로젝트의 채팅 목록 테스트 화면입니다. 크게 4개의 경우가 필요합니다.

1) 채팅 안읽음 표시 

2) 채팅 상대 정보 

3) 채팅 마지막 내용

4) 마지막 채팅 시간 표시

 

채팅 목록 만드는건 정말 단순합니다. 

채팅 목록은 간단하게 RecyclerView를 사용해줍시다. 

RecyclerView 만드는 코드는 따로 정리하지 않겠습니다.

(너무 많은 예제가 있기 때문에 정리가 필요없음)

 

위 layout을 보면 프로필 사진 우측 하단에 작은 붉은점이 보일 겁니다.

저 표시가 채팅을 읽거나, 읽지 않았을 때를 구별해줍니다.

 

위에 말했던 4가지 데이타들을 채워줍니다.

 

** 주의 할점은 채팅과 같이 데이터 변화가 빠른 것은 RecyclerView에서 item을 새로 Update할때 

notifyDataSetChanged() 사용을 권장하지 않습니다. 다른 함수나 혹은 DiffUtill 사용할 것을 권장합니다. **

 

아래와 같이 DB를 만듭니다. 채팅방 DB입니다. 

data class TempChatRoom(
    val id: String? =null,
    //채팅방에 참가한 유저들 1:1방 일시 두명의 유저ID만 있음
    val users: MutableList<String>? =null ,
    // 마지막 chat가 올라온 시간
    val lastChat: Timestamp? =null,
    // onStop 때마다 TimeStamp 값 갱신
    val userLastVisited: Map<String, Timestamp>? = null
    // 나의 index에 해당하는 userLastVisited가 lastChatTimeStamp보다 작으면 '읽지 않음' 표시
)

 채팅 DB는 아래와 같이 만듭니다.

data class TempChat (
  var id: String? = null,
  var user: String? = null,
  var meg: String? = null,
  var crateAt: Timestamp? = null,
)

 

두개의 DB가 준비되었다면 FireStore의 db구조를 활용합시다.

FireStore는 콜렉션, 도큐먼트,데이타 3가지 구조를 가지는데 더 깊은 depth로 쉽게 데이터를 만들 수 있습니다.

콜렉션 -> 도큐먼트 -> 데이타 and 콜렉션 -> 도큐먼트 -> 데이타 and 콜렉션 

이런식으로 활용이 가능합니다.

 

콜렉션 -> 도큐먼트 -> 데이타or 콜렉션 -> 

Chat을 클릭하면 채팅 목록들을 도큐먼트로 지정할 수 있습니다. 

 

그래서 FireStore 의 특징을 활용한 채팅은 이런 구조를 띕니다. 

위와 같이 채팅방 콜렉션 -> 채팅방 목록 -> 데이타 or 채팅 콜렉션 -> 채팅 목록 -> 데이터 형태로 depth를 지정해서 효율적으로 사용할 수 있습니다. noSql은 Join기능이 안되기 때문에 위와같은 데이터 구조를 효율적으로 사용하는 편이 좋습니다. 

 

위에 적어놨던 db를 같이 보면서 정리 해보도록 하겠습니다. 

data class TempChatRoom(
    val id: String? =null,
    //채팅방에 참가한 유저들 1:1방 일시 두명의 유저ID만 있음
    val users: MutableList<String>? =null ,
    // 마지막 chat가 올라온 시간
    val lastChat: Timestamp? =null,
    // onStop 때마다 TimeStamp 값 갱신
    val userLastVisited: Map<String, Timestamp>? = null
    // 나의 index에 해당하는 userLastVisited가 lastChatTimeStamp보다 작으면 '읽지 않음' 표시
)
data class TempChat (
  var id: String? = null,
  var user: String? = null,
  var meg: String? = null,
  var crateAt: Timestamp? = null,
)

1) 채팅 안읽음 표시

-> 이부분은 제가 아닌 다른 팀원이 해결한 부분입니다.TempChatRoom의 userLastVisited필드를 이용합니다. 

Map의 특성을 사용해서 각각의 userId를 key값으로 timeStemp를 저장합니다. 안드로이드의 특성인 라이프사이클을 이용한것인데, 채팅방에 들어가서 onStop이 호출시 이 필드의 timeStemp를 새로 갱신해줍니다.

 

  그 후 마지막에 TempChat의 createAt이  TempChatRoom의 필드 timeStemp에 기록된 time보다 더 늦게 왔다면 붉은색 표시를 visible 하고 반대라면 gone으로 둡니다. 

 

2) 채팅 상대 정보 

내가 포함된 TempChatRoom 목록을 가져온 뒤 users에서 나를 제외한 상대방의 userId 정보를 기준으로 파이어베이스에서 데이터를 가져와 줍니다. 

 

3) 채팅 마지막 내용

채팅방 콜렉션 -> 채팅방 목록 -> 데이타 or 채팅 콜렉션 -> 채팅 목록 -> 데이터  와 같은 구조를 살펴보면 답이 나옵니다. 채팅방의 정보만 알면 타고 들어가서 채팅 목록중에 마지막 index를 가져와서 표시해주면 됩니다. 

   FirebaseFirestore.getInstance().collection("TempChatRoom").document(roomID.toString())
            .collection("TempChat").document().set(chat).addOnCompleteListener {
    .....
    ....
            }

4) 마지막 채팅 시간 표시

TempChatRomm의 createAt를 사용해줍니다. 

그리고 채팅방의 기본인 시간순으로 sort를 해주면 됩니다. 

FireStore의 실시간 수신 대기 함수안에서 sort를 사용한다면 서버에 있는 지정 콜렉션이 변경이 있을 시 알아서 시간순으로 변경이 됩니다.

 

위와 같이 설정해주면 됩니다. 

채팅방 내부는 List클릭시 같이 chat데이터를 넘겨줘서 다음화면에서 리스트뷰에 채팅내역들을 뿌려주면 끝입니다.

채팅도 마찬가지로 리싸이클러뷰의 데이타 갱신 함수를 잘 가려서 쓰거나 DiffUtill를 권장합니다.

 

이상 오늘 했던 작업을 정리했습니다.

주말에 사이드 하니까, 기쁩니다...?