[Android+Firebase] Android 앱에서 데이터베이스 읽기

2-pi-r·2023년 12월 18일
0

나는 보안 규칙을 수정해서 쓰기 권한을 없앴으니까 읽기만 할 수 있다.

참고자료 (공식 문서)

1. 데이터베이스를 참조해서 데이터 스냅샷 받아오기

기본 문법

  • onCreate
    • main 같은 함수라고 이해했다. onCreate 밖에서 어떤 함수를 정의하면, 이 안에서도 꼭 한 번 실행해야 한다. 안 그러면 함수 정의만 해놓고 main에서 한 번도 호출 안 하는 거다.
  • getReference
    • 인수의 기본값은 root(즉 "/")이다. 만약 "exKey"를 넣으면 root 바로 아래의 "exKey"라는 key를 참조하게 된다.
    • 해당 위치 + 하위 데이터를 모니터링한다고 생각하면 된다.
  • addValueEventListener
    • JAVA 문법에서 이벤트 리스너 추가하는 거 모르는 사람은 개념 한 번 훑어보고 오는 걸 추천한다.
    • 실시간으로 DB와 소통하려면 이걸 쓰면 된다.
    • 만약 그게 아니라 DB에서 한 번 읽어오고 마는 거라면 이거 대신 addListenerForSingleValueEvent 쓰면 된다. 다른 부분은 다 똑같다.
    • onDataChange
      • Firebase Realtime Database는 깃처럼 데이터베이스의 스냅샷을 찍는데, 그걸 dataSnapshot이라고 한다.
      • 처음에 한 번, 그 후로 데이터가 바뀔 때마다 한 번씩 호출된다.
    • onCancelled
      • 이때 읽기 권한이 없으면 Cancel되면서 이 함수가 호출된다.
  • 디버깅
    • 바로 이전 게시글에서 설명했듯, System.out.println 해서 프린트하면 Logcat에서 확인할 수 있다.
package ~~;

import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;

import com.google.firebase.FirebaseApp;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;

public class MainActivity extends AppCompatActivity {
    private FirebaseDatabase mDatabase;
    private DatabaseReference mReference;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // 기본 설정 (activity_main 파일의 내용을 앱 화면에 보여줌.)
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 데이터베이스에서 값 읽어오기
        FirebaseApp.initializeApp(this);
        mDatabase = FirebaseDatabase.getInstance();
        mReference = mDatabase.getReference(); // root를 참조

        mReference.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                System.out.println("데이터 성공적으로 받아옴");
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                System.out.println("에러");
            }
        });
    }
}

ERROR

제대로 썼는데! 저 코드에 문제가 없는데!! 데이터베이스를 아무리 수정해봐도 onDataChange 함수가 아예 호출되지 않는 문제가 있었다.

원인

알고 보니 Logcat에 이런 게 찍혀있었고

Firebase Database connection was forcefully killed by the server. Will not attempt reconnect. Reason: Database lives in a different region. Please change your database URL to https://miu404-whataretheydoingnow-default-rtdb.asia-southeast1.firebasedatabase.app

챗GPT한테 물어보니까 이렇다고 한다.

이 경고는 Firebase Database의 연결이 서버에 의해 강제로 종료되었고, 재연결을 시도하지 않을 것이라고 알려주고 있습니다. 그 이유는 "Database lives in a different region"이라고 명시되어 있습니다. 이는 데이터베이스가 서버와 다른 지역에 위치해 있음을 나타냅니다.

Firebase 프로젝트 만들 때 내가 위치를 싱가포르로 선택했는데, 이때 US(미국)을 선택한 게 아니면 이런 문제가 발생한다고 한다.

해결 방법

  • 검색 키워드 : Database lives in a different region.

  • 참고자료 : 스택오버플로우

    • 방법을 2가지 알려줬는데, url을 직접 지정하는 방법은 자꾸 오류가 났다. 그래서 다른 방법을 썼더니 됐다.

    • 간단하다. google-services.json 파일을 다시 다운받으면 된다.

  • 자세한 과정은 아래와 같다.

    1. 프로젝트 설정으로 이동한다.
    2. 스크롤을 내리고, google-services.json 파일을 다시 다운받는다.

    3. google-services.json 파일을 [프로젝트 폴더]-[app 폴더] 아래로 옮긴다.

끝.

2. 스냅샷으로부터 데이터를 읽어들이고, JAVA Hashmap에 저장하기

기본 문법

data가 (string, string) 쌍으로만 이루어져 있을 때

import com.google.firebase.database.GenericTypeIndicator;
import java.util.HashMap;

// (중략)

GenericTypeIndicator<HashMap<String, Object>> genericTypeIndicator = new GenericTypeIndicator<HashMap<String, Object>>() {}; // GenericTypeIndicator를 사용하여 제네릭 유형을 지정

// onDataChange 함수 안에서
HashMap<String, Object> data = dataSnapshot.getValue(genericTypeIndicator); // GenericTypeIndicator를 사용하여 DataSnapshot에서 데이터를 가져오기

이걸 System.out.println(data);로 print해보면 이렇게 된다.

data가 (string, object) 쌍일 때

0개의 댓글