본문 바로가기
앱 제작/키워드 알림 앱

Firebase 데이터베이스 딜레이 문제 해결(= 반환 값이 null일 때)

by Kim Juhwan 2021. 1. 3.

 

파이어 베이스를 사용해보는 것이 이번이 두 번째인데

너무나도 바보 같은 짓으로 삽질을 무진장 해버려서 기록을 남기려고 한다.

그리고 저 처럼 혼자 인터넷으로 공부해서 옆에서 올바른 방법을 지적해 줄 사람이 없는 분들을 위해 남깁니다.

 

 

 


 

1. 첫번째 삽질

    private fun importKeywords(){
        FirebaseDatabase.getInstance().reference
            .child("keywords")
            .addValueEventListener(object : ValueEventListener {
                override fun onCancelled(p0: DatabaseError) {
                    
                }

                override fun onDataChange(p0: DataSnapshot) {
                    // 파이어베이스에서 데이터를 읽어옴
                    num = (대충 값을 가져오는 코드)
                }
            })
        // 읽어온 데이터를 리턴함
        return num
    }

내가 처음에 의도하고자 했던 것은

내가 데이터베이스에서 값을 읽고 싶을 때 importKeywords 메서드를 호출하고

num에다가 값을 저장한 다음 return 해주는 것이었다.

근데 내 예상과는 다르게 자꾸 반환 값이 null로 뜨는 문제가 생겼다.

 

그래서 여기 뜯어보고 저기 뜯어보고 별짓을 다 해보다가

"아! 파이어 베이스에서 데이터를 읽어오는 시간이 느려서 기다리다가 지쳐서 먼저 return 했구나!"라고 생각했다.

 

데이터를 불러오는 것은 비동기식으로 작동하기 때문에 반환 값은 항상 null이 된다.

 

아래 링크는 나처럼 삽질한 외국인들이 질문한 게시물이다.

 

wait until firebase retrieves data

I want to build a method that returns a child value in FireBase. I tried to do something like this: public String getMessage(){ root.child("MessagesOnLaunch").child("Message").

stackoverflow.com

 

 

How to return DataSnapshot value as a result of a method?

I don't have much experience with Java. I'm not sure if this question is stupid, but I need to get a user name from Firebase realtime database and return this name as a result of this method. So, I

stackoverflow.com

 

 

2. 두 번째 삽질

    private fun importKeywords(){
        FirebaseDatabase.getInstance().reference
            .child("keywords")
            .addValueEventListener(object : ValueEventListener {
                override fun onCancelled(p0: DatabaseError) {
                    
                }

                override fun onDataChange(p0: DataSnapshot) {
                    (값을 가져오는 코드)
                    (값을 변화시키는 코드)
                }
            })
    }

리턴된 값으로 하고 싶었던 작업이 값을 변화시켜서 다시 업로드하는 것이었다.

예를 들면, '1'이라는 값을 읽어와서  '+1'을 하고 다시 데이터베이스에 저장하고 싶었다.

값을 리턴하는 게 안되니까 이렇게 onDataChange 안에 연달아서 코드를 작성했다.

결과는?

난 더하기 1만 하고 싶었는데 숫자가 미친 듯이 올라갔다. 무한루프에 빠져버린 것이다.

 

 

 

3. 해결 방법

그 이후로 이것저것 시도해보다가 나의 무지함을 깨달았다.

나는 여태까지 "addValueEventListener = 데이터베이스에서 값을 불러올 때 쓰는 거"라고 생각했다는 것이다.

정확히 말하자면, 값의 변화가 있으면 알려주는 리스너이다.

 

버튼 눌림을 감지하는 setOnClickListener도 한 번 등록해 놓으면 이벤트가 발생할 때 알려주는 것처럼

addValueEventListener도 한 번 등록해 놓으면 이벤트(데이터의 변화)가 발생할 때 알려주는 것이다.

데이터가 필요할 때마다 부르는 메서드 같은 놈이 아니라는 것이다.

 

두 번째 삽질 때 무한루프에 빠졌던 이유가

값을 변화시키니까 -> 리스너가 onDataChange를 호출하고 -> 또 값을 변화시키고 -> 리스너가 on DataChange를 호출하고 -> ... 반복된 것이다.

 

 

class MainActivity : AppCompatActivity() {
    (전역변수)
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        FirebaseDatabase.getInstance().reference
            .child("keywords")
            .addValueEventListener(object : ValueEventListener {
                override fun onCancelled(p0: DatabaseError) {
                    
                }

                override fun onDataChange(p0: DataSnapshot) {
                    (값을 가져와서 전역변수에 저장)
                }
            })
    }
}

결국엔 그냥 위 코드처럼 딱 한 번만 리스너를 등록하면

실시간으로 데이터베이스의 값 변화를 감지해서

만약 변화가 있다면 onDataChange를 그때그때 호출해 줄 것이기 때문에

전역 변수에 저장된 값도 그때그때 바뀐다는 것이다.

 

 

 

세상에 이걸 몰라서 하루 종일 고생한 거 생각하면 어이가 없다.

대체 난 이걸 왜 생각 못했지?...

 


 

혹시 나처럼 바보 같은 생각을 하지 않았는데도

진짜 파이어 베이스의 딜레이 (대기 시간) 때문에 문제가 생기는 부분이 있다면

 

1. 콜백 함수

 

[Android Studio] 파이어베이스 데이터 로드 대기 (Wait to load data from firebase in android)

" English Explain exist below. Please Scroll Down " 파이어베이스는 서버가 필요하지만 번거롭거나, 백엔드 지식이 없을 때 사용할 수 있는 편리한 기능을 제공한다. 하지만 API에 있는 정보만으로는 원활한

satisfactoryplace.tistory.com

 

2. EventBus

 

이렇게 해결한 분들이 있다고 하니 참고하면 좋을 것 같다.

반응형

댓글