DetailActivity.kt 변경 전
class DetailActivity : AppCompatActivity() {
// DetailActivity 클래스의 멤버 변수들을 선언
lateinit var binding: ActivityDetailBinding // 뷰바인딩 초기화
lateinit var detailDB: DatabaseReference // FB Realtime DB와 연동하기 위한 레퍼런스를 초기화
private lateinit var dataList: MutableList<UserData> // 유저 목록을 저장 위한 MutableList를 초기화. 유저 데이터는 RecyclerView 에 표시됨.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 뷰 바인딩 초기화, 해당 바인딩을 현재 액티비티 레이아웃으로 설정
binding = ActivityDetailBinding.inflate(layoutInflater)
setContentView(binding.root)
detailDB = Firebase.database.reference.child("Users") // FB Realtime DB 초기화하고 "Users" 레퍼런스 가져오기
// RDB 에서 사용자 데이터 가져오기
detailDB.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
// 가져온 데이터를 UserData 객체로 변환
for (snapshot in snapshot.children) {
val user = snapshot.getValue(UserData::class.java)
// 가져온 데이터를 UserData 객체로 변환 후, userList 에 추가
if (user != null) {
dataList.add(user)
}
}
}
override fun onCancelled(error: DatabaseError) {
// DB 가져오는 과정에서 오류 발생 시, 오류 메시지 출력
Toast.makeText(this@DetailActivity, "데이터를 가져오는데 실패했습니다.", Toast.LENGTH_SHORT).show()
}
})
// Intent 에서 userPosition 받음
val userDetail = intent.getParcelableExtra<UserData>("userDetail") as UserData
// userData 를 사용하여 Detail 정보 표시
// ex) nickName 표시하는 TextView 를 찾아서 설정
val detailNickname = binding.DetailTxtNickname
detailNickname.text = userDetail.user_nickName
val detailMbti = binding.DetailTxtMbti
detailMbti.text = userDetail.user_mbti
val detailAge = binding.DetailTxtAge
detailAge.text = userDetail.user_age.toString()
}
}
Detail Activity 변경 후
class DetailActivity : AppCompatActivity() {
// DetailActivity 클래스의 멤버 변수들을 선언
lateinit var binding: ActivityDetailBinding // 뷰바인딩 초기화
lateinit var detailDB: DatabaseReference // FB Realtime DB와 연동하기 위한 레퍼런스를 초기화
private lateinit var nameTextView: AppCompatTextView
private lateinit var ageTextView: AppCompatTextView
private lateinit var genderTextView: AppCompatTextView
private lateinit var mbtiTextView: AppCompatTextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 뷰 바인딩 초기화, 해당 바인딩을 현재 액티비티 레이아웃으로 설정
binding = ActivityDetailBinding.inflate(layoutInflater)
setContentView(binding.root)
// TextView 초기화
nameTextView = binding.DetailTxtNickname
ageTextView = binding.DetailTxtAge
genderTextView = binding.DetailTxtGender
mbtiTextView = binding.DetailTxtMbti
// MainActivity 에서 넘어온 intent 를 받아서 userID 변수에 저장
val userID = intent.getStringExtra("userId")
Log.d("DetailActivity", "userID = $userID")
detailDB = Firebase.database.reference.child("Users") // FB Realtime DB 초기화하고 "Users" 레퍼런스 가져오기
// RDB 에서 사용자 데이터 가져오기 ( 주요 목적은 사용자 ID(uid)를 기반으로 DB에서 해당 user 정보를 찾아내고, 화면 표시 위해 userData에 저장. 한 번에 한 사용자의 정보만 가져옴.)
detailDB.addListenerForSingleValueEvent(object : ValueEventListener { // RDB에서 데이터를 읽어오기 위한 리스너를 설정. 데이터의 한 번 읽기 작업을 수행
override fun onDataChange(snapshot: DataSnapshot) { // 데이터를 성공적으로 읽어왔을 때 호출.snapshot은 데이터베이스에서 가져온 정보(=uid)
Log.d("DetailActivity", "snapshot.exists() = ${snapshot.exists()}") // snapshot.exists()를 통해 스냅샷이 데이터를 포함하는지 여부를 확인
if (snapshot.exists()) { // 데이터 스냅샷 존재 확인. 스냅샷이 데이터 포함 시 이 블록 안으로 진입
lateinit var userData : DataSnapshot
// 사용자 ID에 해당하는 데이터 찾기
if (userID != null) {
userData = snapshot.child(userID) // userID가 null이 아닌 경우, snapshot.child(userID)를 사용하여 snapshot에서 해당 사용자 ID에 해당하는 데이터 스냅샷을 가져옴. 이는 특정 사용자의 데이터를 나타내며, userData 변수에 저장
} else {
// 사용자 정보를 가져오지 못한 경우
Toast.makeText(this@DetailActivity, "사용자 정보를 가져오는데 실패했습니다.", Toast.LENGTH_SHORT).show()
}
// 데이터에서 이름, 나이, 성별, MBTI 정보 가져오기 (RDB 에서 특정 유저 정보를 가져와 변수에 저장하는 부분. DB의 트리 구조와 각 데이터 유형에 맞게 데이터 뽑아옴)
val name = userData.child("user_nickName").getValue<String?>() // userData라는 DataSnapshot에서 "user_nickName"이라는 자식 경로에 있는 값을 가져옴.
val age = userData.child("user_age").getValue<Int?>() // 여기서는 user 데이터 아래에 nickname, age, gender, mbti 라는 자식 경로로 데이터가 저장되어있음
val gender = userData.child("user_gender").getValue<String?>()
val mbti = userData.child("user_mbti").getValue<String?>()
/* Child 는 DB의 트리 구조에서 특정 노드 아래에 위치한 하위 노드.
ex) 유저 정보를 저장하는 "Users"라는 루트 노드가 있고, 각 사용자는 고유한 uid(자식 노드) 아래에 저장.
이 자식 노드들은 다시 "user_nickName", "user_age", "user_gender", "user_mbti"와 같은 하위 자식 노드를 가짐.
이 코드에서 child("user_nickName"), child("user_age"), child("user_gender"), child("user_mbti")를 사용하여 하위 자식 노드로 이동
getValue 함수는 특정 데이터 스냅샷에서 값 가져올 때 사용.
데이터의 형식 지정하고, 해당 형식으로 값을 반환.
여기서는 String 및 Int 형식으로 값을 가져옴. 값이 없는 경우 null 반환 위해 getValue 함수에 String? 및 Int?을 사용.*/
// 가져온 데이터를 TextView에 설정
nameTextView.text = name
ageTextView.text = age.toString()
genderTextView.text = gender
mbtiTextView.text = mbti
}
}
override fun onCancelled(error: DatabaseError) {
// DB 가져오는 과정에서 오류 발생 시, 오류 메시지 출력
Toast.makeText(this@DetailActivity, "데이터를 가져오는데 실패했습니다.", Toast.LENGTH_SHORT).show()
}
})
}
}
변경 전 코드 로그를 찍어보면 RDB 의 uid 는 넘어왔음을 확인했다. intent 도 잘 넘긴 것 같고 userdata 사용하여 detail activity 에 이름, 나이, 성별, mbti 만 뿌리면 되는데 텍스트가 표시되지 않고 공백으로 넘겨지기만 했다.
DB 구조는 아래와 같다.
if 부분에 log 를 찍어본 결과 true 가 반환되었고 If 문은 실행되는 것을 알 수 있었다. snapshot.exist(user_nickname)을 찍었더니 닉네임도 잘 넘어왔다. childCount 를 찍어본 결과 3이 찍혔고 db 확인 결과 users 아래 uid 3개가 있었는데 그 개수를 반환한 것으로 보여진다.
if (userID != null) {
userData = snapshot.child(userID)
}
if 부분에 snapshot.child 를 이용해 1가지 uid 만 넘어올 수 있게 한 다음
val name = userData.child("user_nickName").getValue<String?>()
val age = userData.child("user_age").getValue<Int?>()
val gender = userData.child("user_gender").getValue<String?>()
val mbti = userData.child("user_mbti").getValue<String?>()
userData.child("") 를 이용해 유저의 디테일 항목을 가져올 수 있게 바꾸었다.
UserData.kt
package com.example.mbti_talk
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
// FB 와 연결되어 있습니다.
@Parcelize
data class UserData(
val user_email: String = "",
val user_age: Int = 0,
val user_nickName: String = "",
val user_uid: String = "",
val user_gender: String = "",
val user_mbti: String = "",
val user_profile: String = ""
) : Parcelable