0

I am developing a system that allows the user to search for a movie and get the average of the ratings that various users have given to that movie. The system is not too complicated. When a user creates a post that post will have an id and a title (and other data that we don't need now) and these two following structures will be created:

  root --- posts 
             |
             --- uid (c)
                  |
                  --- userPosts (d)
                        |
                        --- postId (c)
                        |     |
                        |     --- title: "Post Title"
                        |     |
                        |     --- date: 4/06/2021
                        |
                        --- postId (d)
                              |
                              --- title: "Post Title"
                              |
                              --- date: 08/06/2021
                              |
                              --- description: "this is the description of the post"
                              [...etc]

and this:

root --- filtrofos
              |
              ---filName
                        |
                         ---**Title Post** 
                                        |
                                        --uid
                                        | 
                                        --uid
                                        ...etc

At this point with a query I go to fetch all the user Ids of the users who posted the post (the film review) with the name that the user searched for and for each ID found I go to search for the desired post I use a whereEqualTo ( "title", name of the film searched)

At this point I find myself inside the posts with the desired name (that is the name searched by the user) so I take the evaluation field each time and I go to add it to a variable for each round so as to make the sum of the evaluations. Now I just have to do the average. The problem is that I used queries with add on complete listener that are executed several times with a for loop, i can't figure out when the for loop ended and i can't get my value. Because if I tried to declare a variable outside of all of this and then tried to use it where I need it, I'd get this: Variable 'sum' is accessed from within inner class, needs to be final or effectively final

Would anyone have an idea how I could get the sum of all the evaluations outside the for loop?

This is the code described above:

int somma = 0;
FirebaseFirestore.getInstance().collection("filtroFoS").document("filName").collection(txtFilmOrSer.getText().toString()).get().addOnCompleteListener(new OnCompleteListener < QuerySnapshot > () {
@Override
public void onComplete(@NonNull Task < QuerySnapshot > task) {
  if (task.isSuccessful()) {

    if (task.isSuccessful()) {
      for (QueryDocumentSnapshot document: task.getResult()) {
        //Toast.makeText(activity_filtroFilm.this, document.getId(), Toast.LENGTH_SHORT).show();

        String uId = document.getId().toString();

        Query userPostsRef = FirebaseFirestore.getInstance().collection("post").document(document.getId()).collection("userPosts").whereEqualTo("title", txtFilmOrSer.getText().toString());
        userPostsRef.get().addOnCompleteListener(new OnCompleteListener < QuerySnapshot > () {
          @Override
          public void onComplete(@NonNull Task < QuerySnapshot > task) {

            if (task.isSuccessful()) {
              String postID = "";
              for (QueryDocumentSnapshot document: task.getResult()) {
                //Toast.makeText(MainActivity.this, document.getId() + "", Toast.LENGTH_SHORT).show();
                postID = document.getId();
                // Toast.makeText(activity_filtroFilm.this, postID + "", Toast.LENGTH_SHORT).show();

                FirebaseFirestore.getInstance().collection("post").document(uId).collection("userPosts").document(postID).get().addOnCompleteListener(new OnCompleteListener < DocumentSnapshot > () {
                  @Override
                  public void onComplete(@NonNull Task < DocumentSnapshot > task) {
                    String valutation = task.getResult().getString("valutation");
                    somma += Integer.parseInt(valutation);

                  }
                });

              }

              Toast.makeText(activity_filtroFilm.this, sommas[0] + "", Toast.LENGTH_SHORT).show();

              String finalPostID = postID;

            }
          }

        });

      }
    }

  }
}

});

}
});
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Conta
  • 236
  • 1
  • 6
  • 21

1 Answers1

1

I tried to declare a variable outside of all of this and then tried to use it where I need it

This won't work. Any code that needs the data from the database, needs to be inside the callback.

i can't figure out when the for loop ended

A common way of doing this is to either use Tasks.whenAll() or simply keep a counter of how many items you have already loaded.

So in your innermost callback, that'd look something like this:

FirebaseFirestore.getInstance().collection("post").document(uId).collection("userPosts").document(postID).get().addOnCompleteListener(new OnCompleteListener < DocumentSnapshot > () {
  @Override
  public void onComplete(@NonNull Task < DocumentSnapshot > task) {
    String valutation = task.getResult().getString("valutation");
    somma += Integer.parseInt(valutation);
    if (completedTaskCount++ == totalTaskCount) { //  Check if we're done
      ... Do what you need with the somma variable
    }
  }
});

Also see:

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks for your answer. I hadn't thought about using Tasks.whenAll (), it actually seems like a good solution. As soon as I can I test it. – Conta Jul 09 '21 at 07:01