[일일이] firebase realtime database 연결

두리두두·2024년 6월 15일
0

TIL

목록 보기
14/15
  • 리사이클러뷰에 파이어베이스에 저장되어있는 애들을 가져오려한다.

🔥 구조

  • 일정을 써서 파이어베이스에 저장을 하기 위해서는 data class로 Diary를 만들고, 이 구조와 똑같이! firebase에도 구성을 해놓는다.
  • 추가할때나 읽어올때나 Diary class는 필참! 여기에 저장을 한 후 객체 단위를 파이어베이스에 넘기면 된다.

🔥 firebase realtime database 연결하기

1. 파이어베이스 설정

  • DB 구조를 정해서 짜준다.
  • 나는 싱가폴 데이터센터, 접근 비허용으로 하고 firebase authentication으로 로그인한 사람만 Read,Write가 가능하도록 설정하였다.
  • 접근 규칙
{
   "rules": {
    ".read": "auth != null",
    ".write": "auth != null"
  }
}

2. 인스턴스 생성

  • 먼저 파베를 사용할 프래그먼트에 인스턴스를 생성해준다.
  • getInstance로 url을 넣어주면 되고,
  • getReference에 사용할 경로를 넣어주면 된다.
 private fun initFirebase() {
        try {
            userId = "BKNnNTkD5kgW1VILsAtiib5Tpks2"
            // Firebase Database 인스턴스 초기화
            database = FirebaseDatabase.getInstance("https://oneone2-4660f-default-rtdb.asia-southeast1.firebasedatabase.app")
            diaryRef = database.getReference("users/$userId/diaries")
            Log.d("LIST++", "IN initFirebase")

            // 데이터 요청
            getFBContentData()
            Log.d("LIST++", "after getFBContentData")
        } catch (e: Exception) {
            Log.e("LIST++", "Firebase initialization failed", e)
        }
    }

Write

  • Diary 클래스에 값을 넣어주고 push하면 된다.
 // 예시로 사용할 다이어리 데이터
  val diary = Diary(
            contentId = 4,
            title = "Fourth Diary",
            content = "Content of the fourth diary",
            timestamp = "2024-06-28",
            photoUrl = "https://www.google.com/url?sa=i&url=http%3A%2F%2Fs.blip.kr%2Fc%2F8287ef00&psig=AOvVaw1fTSz_x3W-KyNi7o5BeTXI&ust=1718527711483000&source=images&cd=vfe&opi=89978449&ved=0CBEQjRxqFwoTCLia79-c3YYDFQAAAAAdAAAAABAE"
        )

        // 새로운 다이어리 추가
        val newDiaryRef = diaryRef.push()
        newDiaryRef.setValue(diary)

Read

  • valueEventListener로 데이터를 불러온다. onDataChange에서 snapshot을 활용해 가져온 후 미리 만들어둔 Diary 타입의 리스트에 넣어주고, 그걸 어답터로 보낼 것이다.
    private fun getFBContentData() {
        Log.d("LIST++", "IN getFBContentData")
        val postListener = object : ValueEventListener {
            override fun onDataChange(snapshot: DataSnapshot) {
                diariesList.clear()
                // 데이터 순회하며 저장
                for (diarySnapshot in snapshot.children) {
				// Diary 객체 저장
                  val diary = diarySnapshot.getValue(Diary::class.java)
                   if (diary != null) {
                        // 리스트에 저장
                        diary?.let { diariesList.add(it) }
                   		}
                    }
                     //notifyDataSetChanged()를 호출하여 adapter에게 값이 변경 되었음을 알려준다.
                  diaryAdapter.submitList(diariesList)
                }

                override fun onCancelled(error: DatabaseError) {	
                // 미정
                }
            }
      diaryRef.addValueEventListener(postListener)


    }

🔥 새로 안 것..

  1. 바로 보여주는게 아니라 앱에서 정의된 data class가 있어야 어답터에 리스트로 넘겨줄 수 있다.

  2. 파이어베이스에 정의된 데이터들과 data class의 필드가 정확히 일치해야한다!

  3. 앱 단위 config에서 초기화를 해줘야한다.

class ApplicationClass : Application() {
    override fun onCreate(){
        super.onCreate()
        Log.d("TEST++", "ApplicationClass")
        FirebaseApp.initializeApp(this)
       UserRepository.initialize(this)
    }
}
  1. 아직 헷갈리는 것..
  • lateinit 초기화와 얘를 초기화해야하는 위치 (onViewCreated냐 어디냐 등... 생명주기가 간단한 것 같지만 은근 중요한것같다)

🔥 파이어베이스 구조에 대한 고민

  • Firebase Realtime Database는 JSON 트리 구조로 데이터를 저장합니다.
  • 데이터베이스의 각 경로는 하위 경로를 포함할 수 있습니다.

사용자 기준으로 데이터 구성하기 vs 모든 데이터를 하나의 경로에 저장하기

1. 사용자 기준으로 데이터 구성하기

{
  "users": {
    "user123": {
      "diaries": {
        "diaryId1": {
          "contentId": 1,
          "title": "First Diary",
          "content": "Content of the first diary",
          "timestamp": "2024-06-25",
          "photoUrl": "https://example.com/photo1.jpg"
        },
        "diaryId2": {
          "contentId": 2,
          "title": "Second Diary",
          "content": "Content of the second diary",
          "timestamp": "2024-06-26",
          "photoUrl": "https://example.com/photo2.jpg"
        }
      }
    }
  }
}
  • 장점:
    각 사용자마다 별도의 데이터 경로를 가질 수 있어 데이터 관리가 용이합니다.
    사용자 간의 데이터 격리를 보장할 수 있습니다.
    사용자의 데이터를 효율적으로 쿼리하고 관리할 수 있습니다.
  • 단점:
    데이터가 분산되어 있어서 특정 사용자의 모든 데이터를 한 번에 가져오려면 추가적인 쿼리가 필요할 수 있습니다.
    데이터베이스 구조가 복잡해질 수 있습니다.
    2. 모든 데이터를 하나의 경로에 저장하고 userId 추가 저장하기
{
  "diaries": {
    "diaryId1": {
      "userId": "user123",
      "contentId": 1,
      "title": "First Diary",
      "content": "Content of the first diary",
      "timestamp": "2024-06-25",
      "photoUrl": "https://example.com/photo1.jpg"
    },
    "diaryId2": {
      "userId": "user123",
      "contentId": 2,
      "title": "Second Diary",
      "content": "Content of the second diary",
      "timestamp": "2024-06-26",
      "photoUrl": "https://example.com/photo2.jpg"
    },
}
  • 장점:
    모든 데이터가 한 경로에 저장되어 간단하게 데이터를 관리할 수 있습니다.
    데이터베이스 구조가 단순해질 수 있습니다.
  • 단점:
    데이터가 많아질 경우 한 경로에서 데이터가 과도하게 커질 수 있습니다.
    특정 사용자의 데이터만을 쿼리할 때 추가적인 필터링이 필요할 수 있습니다.
    사용자 간의 데이터 격리를 보장하기 위해 추가적인 조치가 필요할 수 있습니다.
    결정 방법
    데이터의 접근 패턴과 애플리케이션의 요구사항을 고려하여 결정해야 합니다. 일반적으로 다음 사항을 고려할 수 있습니다:

결론

  • 사용자 기준으로 데이터 구성:
    - 사용자 간의 데이터 격리가 필요하다면 사용자 기준으로 데이터를 구성하는 것이 좋습니다.
    - 사용자의 데이터를 개별적으로 관리하고, 특정 사용자의 데이터만 쉽게 가져올 수 있습니다.
  • 모든 데이터를 하나의 경로에 저장:
    - 데이터의 복잡성이 낮고, 사용자 간의 데이터 격리가 필요하지 않다면 모든 데이터를 하나의 경로에 저장하는 것이 간편할 수 있습니다.
    - 특정 사용자의 데이터를 쿼리할 때 추가적인 필터링이나 데이터 구조 변경이 필요할 수 있습니다.

=> 어차피 난 사용자별로만 보여주면 되니 user별로 하위에 diaries들을 두는 것으로 결정했다! 첨엔 2번으로 했는데 생각해보니 유저별로 두는 것이 더 편할 것 같았다.


파이어베이스 세팅 위치?

  • 2024.06.23
  • 아무생각업이. 파이어베이스 init을 calender, list 프래그먼트에서 각각 하고 있었다. 근데 이제 삭제를 추가하려고 보니 이걸 어답터에서 하는건 아닌 것 같아 챗지피티에게 물어보니 뷰모델에서 하란다. 생각해보니 뷰모델에서 셋팅해뒀으면 한방에 처리됐을거다 ㅜㅜㅜ <<리팩토링 시급 ㄷ
  • 결국 난 뷰모델, 프래그먼트 2개에서 각각 파이어베이스 설정해서 저장하고있던거다 ㄷ 바보바보
profile
야금야금 앱 개발자

0개의 댓글