0

I'm trying to build a movie app, in which there will be reviews and ratings of other users stored on firebase realtime database.

The idea is whenever the user open a movie, my app will query all the ratings of that movie with a given movieId by iterating through its child nodes.

Here is the code to get data from firebase.

fun getAllRating(movieId : String) : MutableLiveData<RatedMovie>{
        var userRating: MutableLiveData<RatedMovie>? = null
        val ratingRef : DatabaseReference = firebaseDatabase.reference.child("RatedMovie").child(movieId)

        Timber.d(movieId)

        ratingRef.addValueEventListener( object : ValueEventListener{

            override fun onDataChange(snapshot: DataSnapshot) {

                Timber.d("start getting ratings")

                for (dataSnapshot : DataSnapshot in snapshot.children) {

                    var userId : String = dataSnapshot.key.toString()

                    Timber.d(userId)

                    //getting user info from user node with userId stored in RatedMovie node
                    var userRef : DatabaseReference = firebaseDatabase.reference.child("User").child(userId)
                    var username =
                        userRef.child("firstname").get().toString() + " " + userRef.child("lastname").get().toString()

                    Timber.d(username)

                    var userImage =
                        userRef.child("avatar_uri").get().toString()

                    Timber.d(userImage)

                    var ratingScore = dataSnapshot.child("ratingScore").value.toString()

                    Timber.d(ratingScore)

                    var comment = dataSnapshot.child("comment").value.toString()

                    Timber.d(comment)

                    userRating?.value = RatedMovie(username,userImage,ratingScore,comment)

                    Timber.d(
                        "%s %s %s %s",
                        userRating?.value?.username.toString(),
                        userRating?.value?.userImage.toString(),
                        userRating?.value?.ratingScore.toString(),
                        userRating?.value?.comment.toString()
                    )
                    return
                }
            }

            override fun onCancelled(error: DatabaseError) {
                Timber.d(error.toString())
            }

        })

        return userRating!!
    }

I have created checkpoints with the log and according to them, the function can only get to the log showing the movieId .

Here are the nodes. Here are my nodes

This is the error log.

2021-08-20 16:42:47.742 2084-2084/com.group1.movieapplication D/--: ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2021-08-20 16:42:47.743 2084-2084/com.group1.movieapplication D/--: │ Thread: main
2021-08-20 16:42:47.743 2084-2084/com.group1.movieapplication D/--: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2021-08-20 16:42:47.743 2084-2084/com.group1.movieapplication D/--: │ MovieDetailFragment.onViewCreated  (MovieDetailFragment.kt:56)
2021-08-20 16:42:47.743 2084-2084/com.group1.movieapplication D/--: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2021-08-20 16:42:47.743 2084-2084/com.group1.movieapplication D/--: │ tt6264654
2021-08-20 16:42:47.743 2084-2084/com.group1.movieapplication D/--: └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2021-08-20 16:42:47.754 2084-2084/com.group1.movieapplication D/--: ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2021-08-20 16:42:47.754 2084-2084/com.group1.movieapplication D/--: │ Thread: main
2021-08-20 16:42:47.754 2084-2084/com.group1.movieapplication D/--: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2021-08-20 16:42:47.754 2084-2084/com.group1.movieapplication D/--: │ MovieDetailViewModel.getAllRating  (MovieDetailViewModel.kt:53)
2021-08-20 16:42:47.754 2084-2084/com.group1.movieapplication D/--: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2021-08-20 16:42:47.754 2084-2084/com.group1.movieapplication D/--: │ tt6264654
2021-08-20 16:42:47.754 2084-2084/com.group1.movieapplication D/--: └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2021-08-20 16:42:47.756 2084-2128/com.group1.movieapplication I/okhttp.OkHttpClient: --> GET https://imdb-api.com/en/API/Title/k_579ho6ea/tt6264654
2021-08-20 16:42:47.756 2084-2128/com.group1.movieapplication I/okhttp.OkHttpClient: --> END GET
2021-08-20 16:42:47.750 2084-2084/com.group1.movieapplication W/mdb-api.com/...: type=1400 audit(0.0:1830): avc: denied { write } for name="perfd" dev="dm-5" ino=65549 scontext=u:r:untrusted_app:s0:c156,c256,c512,c768 tcontext=u:object_r:shell_data_file:s0 tclass=dir permissive=0 app=com.group1.movieapplication
2021-08-20 16:42:47.784 2084-2084/com.group1.movieapplication D/--: ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2021-08-20 16:42:47.784 2084-2084/com.group1.movieapplication D/--: │ Thread: main
2021-08-20 16:42:47.784 2084-2084/com.group1.movieapplication D/--: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2021-08-20 16:42:47.785 2084-2084/com.group1.movieapplication D/--: │ FirebaseAuthRepository.getAllRating  (FirebaseAuthRepository.kt:62)
2021-08-20 16:42:47.785 2084-2084/com.group1.movieapplication D/--: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2021-08-20 16:42:47.785 2084-2084/com.group1.movieapplication D/--: │ tt6264654
2021-08-20 16:42:47.785 2084-2084/com.group1.movieapplication D/--: └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2021-08-20 16:42:47.789 2084-2084/com.group1.movieapplication D/AndroidRuntime: Shutting down VM
2021-08-20 16:42:47.792 2084-2084/com.group1.movieapplication E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.group1.movieapplication, PID: 2084
    java.lang.NullPointerException
        at com.group1.movieapplication.data.repository.FirebaseAuthRepository.getAllRating(FirebaseAuthRepository.kt:115)
        at com.group1.movieapplication.ui.movieDetail.MovieDetailViewModel.getAllRating(MovieDetailViewModel.kt:54)
        at com.group1.movieapplication.ui.movieDetail.MovieDetailFragment.getMovieRating(MovieDetailFragment.kt:89)
        at com.group1.movieapplication.ui.movieDetail.MovieDetailFragment.onViewCreated(MovieDetailFragment.kt:59)
        at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2987)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:546)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2106)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
        at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
2021-08-20 16:42:47.829 2084-2124/com.group1.movieapplication W/System: Ignoring header X-Firebase-Locale because its value was null.

As the log goes, the function only gets to Timber.d(movieId) which is line 62 before throwing a before throwing a NullPointerException and crash the app without getting any data. It did not even get to the final checkpoint showing all the needed data before the return command.

Am I doing something wrong? Any tip is appreciated.

Long Doan
  • 91
  • 8
  • What exactly in this code doesn't work the way you expect? Tell us what is wrong with shared code. Do you have any errors? – Alex Mamo Aug 20 '21 at 09:39
  • Let me edit my post with the log, I just realized that I forgot to put it in – Long Doan Aug 20 '21 at 09:41
  • 1
    Does this answer your question? [Why does my function that calls an API return an empty or null value?](https://stackoverflow.com/questions/57330766/why-does-my-function-that-calls-an-api-return-an-empty-or-null-value) – a_local_nobody Aug 20 '21 at 09:43
  • @AlexMamo OP is using `return userRating!!` which only gets assigned a value inside the firebase call, isn't it ? – a_local_nobody Aug 20 '21 at 09:44
  • @a_local_nobody As I see, the `userRating` is a LiveData object that can be returned as a result of a method if it's correctly populated. The problem seems to be more related to the fact that is calling get() on reference and then converting it to String. – Alex Mamo Aug 20 '21 at 10:02
  • @a_local_nobody I don't think it does. My code did not even get to the return, which I suspect is because of something related to my queries – Long Doan Aug 20 '21 at 10:02
  • Since you have a `NullPointerException` on it, which line is `FirebaseAuthRepository.kt:115`? – Frank van Puffelen Aug 20 '21 at 14:49
  • @FrankvanPuffelen I don't do android but isn't this an asynchronous issue? The `return userRating!!` at the bottom of the code, which is outside the `addValueEventListener` closure will execute *before* the code within the closure, so userRating will not be populated? I could be totally off base. – Jay Aug 20 '21 at 18:19
  • Ah yeah, that looks suspicious indeed Jay. And it might indeed be the `!!` that causes the `NullPointerException` as `!!` pretty much is you as a dev saying "I am certain this will not be `null`", and then being wrong about it. Good catch Jay! – Frank van Puffelen Aug 20 '21 at 18:22
  • 1
    @LongDoan As Jay pointed out, data is loaded from Firebase asynchronously, and you're not handling that correctly. If you run the code in a debugger or add some logging, you'll see that your `return userRating!!` runs before the `onDataChange` is called. So `userRating` is `null` by the time it runs. The solution is always the same: the code that needs the data from the database must be inside `onDataChange` or be called from there. – Frank van Puffelen Aug 20 '21 at 18:24

0 Answers0