마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

android 와 firebase realitime database의 test중 결과값이 의문입니다.

0 추천

첫번째 사진은 onCreat 함수와 그위 전역변수들입니다.주의해서 봐주셔야할것은 currentUidNickname 변수와  getCurrentUserNickcname() 함수와 바로밑에 Log.d(TAG,currentUidNickcname)입니다.

 

두번째 사진은 첫번째 사진에서 보신 getCurrentUserNickname() 함수입니다. 함수안은 firebase realtimebase에 저장한 값을 제가 원하는 값으로 뽑아내는과정입니다. 함수 이름과 같이 현재 uid값과 저장된 uid값이 같을때 같이 저장한 userNickname값을 첫번째 사진의 전역변수인 currentUidNickname에 대입해주는 일을 합니다.

 

3번째 사진은 첫번째 사진의 Log.d(TAG,cuurentUserNickname)에 출력값입니다.

여기서 의문점은 분명 이 코드는 getCurrentUserNickcname() 밑에 있는데 출력값을 보면 대입이 제대로 되있지 않습니다.제가 알기로는 비동기 방식이라 위에서부터 차례대로 실행이 되는걸로 알고있는데 출력값을 보면 위에서 부터 아래로 실행됬다고 할수없습니다.왜냐하면 함수를 호출하면 대입이 되어야하는데 대입이 되어있지 않습니다. 그래서 제가 생각하기에는 위에서 아래로 차례대로 실행되는건 맞는데 getCurrentUserNickname()에 함수는 realtime databsae에서 값을 가져오기 때문에  값을 가져오는 시간동안 그 밑에 코드를 실행해서 값이 잘 안들어가고있다고 어느정도 추측하고있습니다.그래서 Handler().postDelay 함수로 getCurrentUserNickname() 이 함수에 딜레이를 1초정도 주니까 값이 제대로 들어가는걸 확인하였습니다.그래서 제가 추측한것이 맞는지도 궁금하고 delay를 주지않고 realtime database에서 값을 가져오는 과정까지 작업을 끝내고 그밑에 코드를 실행할수있게 만드는 방법이 있을까 궁금합니다 혹시 아십니까??

2달째 코린이 (380 포인트) 님이 2021년 7월 27일 질문

2개의 답변

0 추천

ValueEventListener가 콜백리스너입니다. 즉, 파이어베이스에서 이벤트가 발생할 때 님이 추가한 ValueEventListener를 통해 파이어베이스가 함수를 호출하는 겁니다. 결과적으로는 비동기로 동작을 하는 겁니다. 다만 ValueEventListener는 백그라운 스레드를 자동으로 메인스레드로 전환해주고 있네요. 모바일앱에서는 메인스레드 안에서만 뷰에 접근이 가능하거든요.

따라서 사용자이름의 로그를 출력하시려면 콜백 안에서 해야 합니다.

추가로 Firebase에는 이미 로그인한 현재 유저를 구할 수 있는 함수가 존재하는 걸로 압니다. 이걸 사용하시는 것이 좀 더 정확할 것 같구요. 코드에서 한두가지 수정했으면 좋을 것 같은 부분이 있는데,

FBAuth.getUid() == datamodel.key

 

코틀린에서 equals 비교는 == 입니다. 그런데 ==는  null safe 라 널과도 비교를 할 수 있기 때문에 Java의 equals보다 사용하기 편리합니다. 아마 안드로이드 스튜디오에서 equals위에서 마우스를 가져다 대시면 equals를 ==로 바꾸라는 힌트를 보실 수 있을 거예요.

currentUidNickname = snapshot.children.find { datamodel ->
    FBAuth.getUid() == datamodel.key
}?.userName

위처럼 Collection의 Extension function을 사용하시면 좀 더 정확하게 원하는 엘리먼트를 찾을 수가 있습니다.

currentUidNickname = snapshot.children.find { datamodel ->
    FBAuth.getUid() == datamodel.key
}?.userName ?: return handleUserNotFound()

private fun handleUserNotFound() {

}

사용자를 찾지 못하는 경우가 생길 수도 있으므로 여기에 대한 예외 처리를 하셔야 할 것 같습니다. 예외 처리는 안정적인 앱을 위해서 상당히 중요한 부분입니다.

spark (227,530 포인트) 님이 2021년 7월 27일 답변
비동기 호출이지만 동기식 호출처럼 바꾸려면 코루틴을 사용하시면 됩니다.
예외 처리를 if(FBAuth.getUid() == datamodel.key){
                     }
                     else{  //여기다가 예외처리        }
else 찾지 못하는 경우 이쪽에다가 예외처리를 해주면 되는거죠??
아니오. 콜렉션 안에서 하시면 안되구, 콜렉션을 다 검색하신 다음 없으면 하셔야 겠죠?
var found = false
for (datamodel in snapshot.children) {
     if (FBAuth.getUid() == datamodel.key) {
          found = true
          break
     }
}

if (!found) {
   // 여기에서 해당 uid가 존재하지 않을 때의 에러처리.
}
음 문제가 또 발생하네요..
0 추천

Firebase에서 현재 유저는 아래처럼 가져오게 되어 있네요.

val user = Firebase.auth.currentUser
user?.let {
    val name = user.displayName
    val email = user.email
    val photoUrl = user.photoUrl
    val emailVerified = user.isEmailVerified
    val uid = user.uid
}

 

그리고 로그인한 유저의 닉네임을 가져오려면 snapshot 전체를 가지고 오지 마시고 Firebase에도 쿼리가 있으니, 그걸 이용하셔서 user.uid랑 일치하는 key를 가진 데이터만 가져오세요.

spark (227,530 포인트) 님이 2021년 7월 27일 답변
파이어스토어를 사용하셨으면 좀 더 강력한 쿼리를 사용하실 수 있겠지만, userId를 가진 유저만 가져오려면 아래처럼 할 수 있을 것 같네요.
mDatabase.child("users").child(userId).get().addOnSuccessListener {
    Log.i("firebase", "Got value ${it.value}")
}.addOnFailureListener{
    Log.e("firebase", "Error getting data", it)
}
아 해보니까 훨씬 간편하네요.파이어스토어도 저런 방식으로 데이터를 가져올수있나요?저런 방식이 쿼리에 select를 사용하는방식이죠???
Firestore는 Firebae Realtime database의 향상된 버전입니다. 쿼리도 많이 보강이 되었습니다.
아하 스냅샷을 전부 가져오는 방법보다 spark님이 알려주신 쿼리를 이용해서 가져오는게 성능도 훨씬 좋겠네요?
...