data class KeyValueElement(
val userId: String,
val userNickName: String,
val content: String,
val createdDate: Date
) {
operator fun get(s: String): String {
return when (s) {
"userId" -> userId
"userNickName" -> userNickName
"content" -> content
"createdDate" -> createdDate.toString()
else -> ""
}
}
}
data class Review(
var markerId: String = "",
var reviewList: MutableList<KeyValueElement> = mutableListOf()
) {
fun addReview(userId: String, userNickName: String, content: String, createdDate: Date) {
reviewList.add(KeyValueElement(userId, userNickName, content, createdDate))
}
}
Firebase 에 위와 같은 Review 타입의 객체를 다음과 같이 저장했었다.
//*********************리뷰 등록 버튼*********************//
binding.submitCommentButton.setOnClickListener {
//입력창 내용 가져오기
...
val review = Review()
review.markerId = id
review.addReview(MainActivity.staticUserId.toString(), MainActivity.staticUserNickname, content, Date())
//리뷰 등록
val db = FirebaseFirestore.getInstance()
val docRef = db.collection("reviews").document(id)
docRef.get()
.addOnSuccessListener { document: DocumentSnapshot ->
if(document != null && document.exists()){
//기존에 문서가 존재하는 경우, 기존의 reviewList 가져옴
val existingReviewList = document.data?.get("reviewList") as MutableList<KeyValueElement>
//새 리뷰를 기존 reviewList에 추가
existingReviewList.addAll(review.reviewList)
//firebase 문서 업데이트
docRef.update("reviewList", existingReviewList)
.addOnSuccessListener {
...
}
.addOnFailureListener { e ->
,,,
}
} else{
//기존 문서가 존재하지 않는 경우, 새 문서 생성
docRef.set(review)
.addOnSuccessListener {
...
}
.addOnFailureListener { e ->
...
}
}
}
}
위에서 보듯, 내가 set으로 Firebase 에 넣기 위해 사용한 데이터는 Review 클래스 타입의 객체였다.
그러나 Firebase 에 데이터를 저장한 후, Firebase에서 가져온 reviewList는 해시맵 객체를 가지고 있는 List 였다(넣을땐 KeyValueElement 객체를 가지는 List였음).
로그: MyAdapter: onBindViewHolder typeof reviewList[position]: class java.util.HashMap
그리고 객체의 타입이 바뀐만큼 KeyValueElement 객체의 createDate: Date 필드는 해시맵에서 Firebase 자체 타입인 com.google.firebase.Timestamp 타입의 값으로 바뀌었다.
data class ReviewData(
val content: String? = null,
val createdDate: com.google.firebase.Timestamp? = null,
val userNickName: String? = null,
val userId: String? = null
)
...
val reviewData = ReviewData(
//저장할때는 KeyValueElement 타입이었지만, 가져올때는 HashMap 타입이다.
//저장할때는 Timestamp 타입이었지만, 가져올때는 com.google.firebase.Timestamp 타입이다.
createdDate = dataFromFirestore["createdDate"] as? com.google.firebase.Timestamp,
userNickName = dataFromFirestore["userNickName"] as String?,
userId = dataFromFirestore["userId"] as String?,
content = dataFromFirestore["content"] as String?
)
따라서 db 에서 가져온 reviewList의 원소들을 변수에 담기 위해 위와 같은 클래스를
선언하여 db에서 가져온 reviewList 의 원소인 해시맵 객체를 아래와 같이 대입해주었다.
try {
if (reviewList != null && position >= 0 && position < reviewList.size) {
//reviewList[Position]이 애초에 DB로부터 HashMap 형태(KeyValueElement 타입 X!!)로 가져와졌기 때문에 해시맵을 이용해야 한다.
//따라서 내가 임의로 만든 KeyValueElement 타입의 객체에 reviewList[position]을 대입할 수 없다.
val dataFromFirestore: HashMap<String, Any> = reviewList[position] as HashMap<String, Any>
Log.d("review", "MyAdapter: typeof reviewList: ${reviewList::class.java}")
for ((key, value) in dataFromFirestore) {
Log.d("review","Key: $key, Value: $value")
}
val reviewData = ReviewData(
//저장할때는 KeyValueElement 타입이었지만, 가져올때는 HashMap 타입이다.
//저장할때는 Timestamp 타입이었지만, 가져올때는 com.google.firebase.Timestamp 타입이다.
createdDate = dataFromFirestore["createdDate"] as? com.google.firebase.Timestamp,
userNickName = dataFromFirestore["userNickName"] as String?,
userId = dataFromFirestore["userId"] as String?,
content = dataFromFirestore["content"] as String?
)
val binding = (holder as MyAdapter.MyViewHolder).binding
binding.commentUserId.text = reviewData.userNickName
binding.commentContent.text = reviewData.content
}
} catch (e: Exception) {
e.printStackTrace()
Log.d("review", "MyAdapter: onBindViewHolder error: ${e}")
}
이후 대입받은 객체를 이용해 뷰홀더의 (아이템) 뷰 객체에 데이터를 출력(입력)해주었다.
해시맵 객체를 가지고 일반 클래스 타입 객체에 대입하는 고생을 했다. try & catch 문을 통해 에러 발생 사유를 알 수 있었다. 다음부턴 빠르게 미리 적용해놓자.
일반 클래스 타입의 객체를 db에 저장했다고 해서, db에서 해당 객체를 가져올때 당연히 동일한 데이터 타입, 동일한 필드 타입으로 가져올거라는 생각을 하지말자.