Problems with Firestore connections executing threads

前端 未结 3 683
旧时难觅i
旧时难觅i 2020-12-11 13:54

First of all, I would like to apologize if the title is misleading. English is not my native language and I wasn\'t sure how to name this post. Now the question:

I

3条回答
  •  遥遥无期
    2020-12-11 14:41

    The problem is not so much caused by multi-thread, as by the fact that data is loaded from Firebase asynchronously. By the time your updateUI function looks at the value of aa, the onComplete hasn't run yet.

    This is easiest to see by placing a few well placed logging statements:

    System.out.println("Before attaching listener");
    docRef.get().addOnCompleteListener(new OnCompleteListener() {
        @Override
        public void onComplete(@NonNull Task task) {
            System.out.println("Got document");
        }
    });
    System.out.println("After attaching listener");
    

    When you run this code it prints

    Before attaching listener

    After attaching listener

    Got document

    This is probably not what you expected, but it explains precisely why aa is unmodified when updateUI checks it. The document hasn't been read from Firestore yet, so onComplete hasn't run yet.

    The solution for this is to move all code that requires data from the database into the onComplete method. The simplest way in your case is:

    public void userExists(String uid) {
      FirebaseFirestore db = FirebaseFirestore.getInstance();
      DocumentReference docRef = db.collection("users").document(uid);
      docRef.get().addOnCompleteListener(new OnCompleteListener() {
        @Override
        public void onComplete(@NonNull Task task) {
            if (task.isSuccessful()) {
                DocumentSnapshot documentSnapshot = task.getResult();
                if (documentSnapshot.exists()) {
                    //Fill layout with the user data and the user linked document data
        
                    //USER DATA
                    txvNombre=findViewById(R.id.nombrePerfil);
                    txvNombre.setText(user.getDisplayName());
                    imvAvatar=findViewById(R.id.imvVistaPerfilAvatar);
                    Picasso.with(VistaPerfilActivity.this)
                            .load(user.getPhotoUrl())
                            .resize(500,500)
                            .centerCrop()
                            .into(imvAvatar);
        
        
                    //HERE GOES THE DOCUMENT DATA
    
                }
            }
        }
      });
    }
    

    Now your code that needs the document only runs after the document is actually available. This will work, but it does make the userExists function a bit less reusable. If you want to fix that, you can pass a callback into userExists that you then call after the document is loaded.

    public interface UserExistsCallback {
      void onCallback(boolean isExisting);
    }
    

    And use that in userExists as:

    public void userExists(String uid, final UserExistsCallback callback) {
      FirebaseFirestore db = FirebaseFirestore.getInstance();
      DocumentReference docRef = db.collection("users").document(uid);
      docRef.get().addOnCompleteListener(new OnCompleteListener() {
        @Override
        public void onComplete(@NonNull Task task) {
            boolean userExists = false;
            if (task.isSuccessful()) {
                DocumentSnapshot documentSnapshot = task.getResult();
                userExists = documentSnapshot.exists();
            }
            callback.onCallback(userExists);
        }
      });
    }
    

    And then invoke that from updateUI with:

    if (user != null) {
      userExists(user.getUid(), new UserExistsCallback() {
        public void onCallback(boolean isExisting) {
          if(isExisting){
            //Fill layout with the user data and the user linked document data
    
            //USER DATA
            txvNombre=findViewById(R.id.nombrePerfil);
            txvNombre.setText(user.getDisplayName());
            imvAvatar=findViewById(R.id.imvVistaPerfilAvatar);
            Picasso.with(VistaPerfilActivity.this)
                    .load(user.getPhotoUrl())
                    .resize(500,500)
                    .centerCrop()
                    .into(imvAvatar);
    
    
            //HERE GOES THE DOCUMENT DATA
    
    
          }else{
    
          }
        } else {
          finish();
        }
      });
    }
    

    As you can see our `` callback is quite similar to the OnCompleteListener of Firestore itself, it's just a bit more tailored to our needs.

    This problem pops up a lot, so I recommend spending some time learning more about it. See:

    • get all table values from firebase null object reference firebase database
    • Setting Singleton property value in Firebase Listener

提交回复
热议问题