gpt4 book ai didi

java - Android - 如何等待 SnapshotListener 完成?

转载 作者:行者123 更新时间:2023-11-30 06:03:26 25 4
gpt4 key购买 nike

我在 Android 应用中使用 Firestore。我创建了一个 User 类,它代表 Firestore 中 users 集合下的一个文档。这是类(class):

public class User
{
private String documentID;
private String email;
private String firstName;
private String lastName;
private String mobilePhone;

private static final String USERS_COLLECTION_NAME = "users";

private static class FieldNames
{
private static final String EMAIL = "email";
private static final String FIRST_NAME = "firstName";
private static final String LAST_NAME = "lastName";
private static final String MOBILE_PHONE = "mobilePhone";
}

private User(String documentID)
{
this.documentID = documentID;
}

private static void checkRequiredStringField(DocumentSnapshot documentSnapshot, String fieldName) throws IllegalArgumentException
{
checkArgument(documentSnapshot.contains(fieldName), "The given documentSnapshot does not contain the required field '%s'.", fieldName);
}

private void attachUpdateEventListeners()
{
FirebaseFirestore.getInstance()
.collection(USERS_COLLECTION_NAME)
.document(documentID)
.addSnapshotListener((documentSnapshot, exception) -> {
if (exception == null)
{
email = documentSnapshot.getString(FieldNames.EMAIL);
firstName = documentSnapshot.getString(FieldNames.FIRST_NAME);
lastName = documentSnapshot.getString(FieldNames.LAST_NAME);
mobilePhone = documentSnapshot.getString(FieldNames.MOBILE_PHONE);
}
else
{
Crashlytics.log(Log.ERROR, createLogTagForClass(getClass()), "Exception occurred while listening for changes on document with ID " + documentID + ". Exception message: " + exception.getMessage());
Crashlytics.logException(exception);
}
});
}

@NonNull
public static Task<DocumentSnapshot> getDocumentSnapshot(@NonNull FirebaseUser firebaseUser)
{
checkNotNull(firebaseUser);
return FirebaseFirestore.getInstance().collection(USERS_COLLECTION_NAME)
.document(firebaseUser.getUid())
.get();
}

public static User fromDocumentSnapshot(@NonNull DocumentSnapshot documentSnapshot) throws IllegalArgumentException
{
checkNotNull(documentSnapshot);
checkRequiredStringField(documentSnapshot, FieldNames.EMAIL);
checkRequiredStringField(documentSnapshot, FieldNames.FIRST_NAME);
checkRequiredStringField(documentSnapshot, FieldNames.LAST_NAME);
checkRequiredStringField(documentSnapshot, FieldNames.MOBILE_PHONE);

User user = new User(documentSnapshot.getId());

user.email = documentSnapshot.getString(FieldNames.EMAIL);
user.firstName = documentSnapshot.getString(FieldNames.FIRST_NAME);
user.lastName = documentSnapshot.getString(FieldNames.LAST_NAME);
user.mobilePhone = documentSnapshot.getString(FieldNames.MOBILE_PHONE);
user.attachUpdateEventListeners();

return user;
}

public String getEmail()
{
return email;
}

public String getFirstName()
{
return firstName;
}

public String getLastName()
{
return lastName;
}

public String getMobilePhone()
{
return mobilePhone;
}
}

此类的想法是从 Firestore 加载它(使用方法 getDocumentSnapshotfromDocumentSnapshot),然后该类检查自身是否有更新(使用方法 >attachUpdateEventListeners)。问题是客户端代码可以在类更新时调用 getter 方法(由于 Firestore 触发的更新),因此客户端可能会获取该字段的过时值。

我正在寻找一种编写如下代码的方法:

public String myGetter()
{
if (isUpdateRunning())
{
waitForUpdate();
}

return myField;
}

但我不知道如何实现两个方法 isUpdateRunningwaitForUpdate

我找到的唯一解决方案是在我的 User 类中放置一个标志 isUpdateRunning,当snapshotListener 启动并在完成时返回 false。然后,在我的 getter 中,如果此标志的值为 true,我将在返回该值之前等待固定的时间(使用 Thread.sleep)。不过,我认为这不是最好的解决方案(也是因为使用 Thread.sleep 我必须处理 InterruptedException)。

private boolean isUpdateRunning;

private User(String documentID)
{
this.documentID = documentID;
isUpdateRunning = false;
}

private void attachUpdateEventListeners()
{
FirebaseFirestore.getInstance()
.collection(USERS_COLLECTION_NAME)
.document(documentID)
.addSnapshotListener((documentSnapshot, exception) -> {
if (exception == null)
{
isUpdateRunning = true;
// omitted code
// re-assigning fields...
isUpdateRunning = false;
}
// omitted code
});
}

public String myGetter()
{
if (isUpdateRunning)
{
Thread.sleep(1000); // how to handle the InterruptedException?
}

return myField;
}

最佳答案

您不能使用这些 boolean 值来做到这一点,并且尝试调用 sleep(1000) 并不能在所有情况下为您提供帮助,在这种情况下它也被称为不好的做法。如果从数据库获取数据的时间超过 1 秒,会发生什么情况?您的应用程序将无限期卡住,这是一种糟糕的用户体验。根据您的连接速度,可能需要几百毫秒到几秒钟的时间才能获得数据。因此无法保证需要多长时间。

How to wait until a SnapshotListener has finished?

Firebase API 是异步,这意味着 onEvent() 方法在调用后立即返回,并且它返回的任务的回调将在一段时间后调用。

为了避免阻塞主线程,解决此问题的一个快速解决方案是仅在 onEvent() 方法中使用这些结果,否则,如果您想等待数据,我建议您查看我的答案的最后一部分 post 其中我解释了如何使用自定义回调来完成它。您还可以看看这个video 为了更好地理解。

关于java - Android - 如何等待 SnapshotListener 完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51825131/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com