[Android/Team] 커뮤니케이션 어플 개발_메인 페이지에서 특정 사용자 클릭 시 firebase 에서 해당 사용자의 정보 불러서 Detail Activity 에 띄우기

이도연·2023년 10월 24일
0

android studio

목록 보기
18/28
post-thumbnail

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

0개의 댓글