当前位置: 首页 > 面试题库 >

Firestore连接执行线程时出现问题

拓拔嘉颖
2023-03-14
问题内容

首先,如果标题误导我,我深表歉意。英语不是我的母语,所以我不确定该如何命名。现在的问题是:

我有一个活动,可显示存储在Firebase项目中有关用户的数据。数据在Firebase用户(显示名称,电子邮件和个人资料图像)和Cloud
Firestore中名为该用户的文档之间分配UID

当此活动开始时,我进行了Firebase谷歌身份验证以获取用户,然后出现了问题。我需要知道用户是否在数据库中有一个链接文档及其附加数据(现有用户),或者他是否需要创建一个链接文档(新用户)。我创建了一种方法来检查是否存在像用户的UID这样的文档。这是方法:

public void userExists(String uid) {
    FirebaseFirestore db = FirebaseFirestore.getInstance();
    DocumentReference docRef = db.collection("users").document(uid);
    docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
        @Override
        public void onComplete(@NonNull Task<DocumentSnapshot> task) {
            if (task.isSuccessful()) {
                DocumentSnapshot documentSnapshot = task.getResult();
                if (documentSnapshot.exists()) {
                    aa = true;
                    aa=true;
                } else {
                    aa = false;
                }
            } else {
                aa = false;
            }
        }
    });
}

aa是在Activity中声明的布尔变量)。

我在下一个方法中调用此方法,以了解是否需要启动新的Activity来创建文档,或者是否可以在当前Activity中显示用户数据而不会出现问题。

private void updateUI(FirebaseUser user) {

    if (user != null) {
        userExists(user.getUid());
        if(aa){
            //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();
    }
}

据我所知,Firestore连接是在新线程中建立的,因此,当UpdateUI(FirebaseUser
user)启动时,aa始终为false,因为userExists(String uid)尚未完成。userExists(String
uid)正常工作,我已经检查了它。

因此,我需要知道如何检查Firestore连接线程是否完成,才能继续执行该应用程序。我尝试使用OnCompleteListener(如代码中所示),但是它不起作用。我也尝试只在userExists(String
uid)方法中编写操作,而不是仅更改aa的值,然后继续使用另一种方法,但是我得到了

从内部类内部访问变量需要声明为final

错误。我试图遵循Android Studio的建议,将变量定为final,但是由于明显的原因,我无法使用它。

提前致谢。


问题答案:

问题不是由多线程引起的,而是由Firebase异步加载数据引起的。等到您的updateUI函数查看的值时aaonComplete尚未运行。

通过放置一些放置良好的日志记录语句,这最容易看到:

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

当您运行此代码时,它会打印

附加监听器之前

附加监听器后

得到文件

这可能不是您所期望的,但恰恰说明了检查aa时为什么未修改的原因updateUI。该文件尚未从Firestore中读取,因此onComplete尚未运行。

此解决方案是移动从数据库中需要的数据的所有码 onComplete方法。在这种情况下,最简单的方法是:

public void userExists(String uid) {
  FirebaseFirestore db = FirebaseFirestore.getInstance();
  DocumentReference docRef = db.collection("users").document(uid);
  docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
    @Override
    public void onComplete(@NonNull Task<DocumentSnapshot> 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

            }
        }
    }
  });
}

现在,需要文档的代码仅在文档实际可用后才运行。这将起作用,但是确实会使该userExists函数的可重用性降低。如果要解决此问题,可以将回调传递
userExists该回调中,然后在加载文档后调用该回调。

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

并将其userExists用作:

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

然后使用以下命令调用它updateUI

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();
    }
  });
}

如您所见,我们的`回调与OnCompleteListener`Firestore本身非常相似,它只是针对我们的需求量身定制了。



 类似资料:
  • 我在Ubuntu 14.04中使用XAMPP for linux。在终端上启动服务时,打印下一个日志: sudo /opt/lampp/lampp启动 "开始XAMPPLinux5.5.30-0... XAMPP:正在启动Apache。。。好啊 XAMPP:正在启动MySQL。。。已经在运行了。 XAMPP:开始ProFTPD...好的。" 我不知道为什么当我第一次启动XAMPPm时,MySQL服

  • 我试图在包含GUI系统的JDK 11.0.2上运行我在Intellij中创建的一个可执行jar文件。我已经安装了Java8和java SDK11.0.2。每当我双击jar文件时,我希望主gui登录屏幕出现,但什么也没有发生。我已经尝试了其他选项,例如尝试通过cmd运行它(它给了我一个访问错误),HKEY_CLASSES_ROOT\jarfile已经有命令:“C:\Program Files\jav

  • 我正在尝试让nutch 1.11执行爬网。我正在使用cygwin在windows 7中运行这些命令。 Nutch正在运行,运行bin/Nutch会得到结果,但当我尝试运行爬网时,会不断收到错误消息。 当我尝试使用 nutch 运行爬网执行时,我收到以下错误: 运行时出错:/cygdrive/c/Users/User5/Documents/Nutch/apache-Nutch-1.11/runtim

  • 我有一个IP地址每次我收到连接失败的消息时,我都尝试了很多连接到该服务器的方法。出于安全原因,我隐藏了用户名和密码。 代码: 我有例外 组织。postgresql。util。PSQLException:连接尝试失败。在org。postgresql。果心v3。连接工厂impl。org上的openConnectionImpl(ConnectionFactoryImpl.java:292)。postgr

  • 我还是nodejs的新手,有些东西不能理解。我有带有代码的db.js文件: 当我尝试这样插入行时: 它会失败,并出现sql语法错误。为什么它失败了,它工作得很好,只是使用了稍微不同的db.js。我在这里寻找简短而正确的解决方案。

  • 我们正在尝试将涡轮机集成到我们的应用程序中。 我下载了1。o、 o样品发布(https://github.com/spring-cloud-samples/turbine/releases/tag/v1.0.0.RELEASE)建造并运行它。我没有连接到eureka(我拥有的其他服务与应用程序yml connect fine中的eureka连接设置相同)。 考虑到也许我应该尝试最新版本的turbi