【问题标题】:How to modify objects of outer class from an inner class so as to retrieve class object from firebase如何从内部类修改外部类的对象,以便从firebase中检索类对象
【发布时间】:2022-01-15 18:12:06
【问题描述】:

我目前正在开发一个与 Firebase 集成的 Android 项目,但是由于 Firebase 侦听器,我正在努力从 Firebase 实时数据库中检索一个类对象。

让我详细说明我的项目,以便您了解它的主要思想。我使用 MVVM 架构,我有 2 个活动,其中一个用于身份验证,另一个用于主要用途。

第一个活动包含注册、登录、密码重置片段 第二个活动包含 4 个片段,用于程序的主要功能

第一个活动中的片段使用共享视图模型“AuthViewModel”,其中包含调用 AuthRepository 对象方法的方法和为片段提供数据的 LiveData 变量

我所有的 Firebase Auth 操作都在这个 AuthRepository 的方法中处理,例如这是 AuthRepository 中的 register 方法,它使用 FireBase Auth 方法注册用户,同时通过创建一个 User 对象将用户添加到实时数据库中。

    public void register(String email , String pass, String username, String department){
    auth.createUserWithEmailAndPassword(email , pass).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
        @Override
        public void onComplete(@NonNull  Task<AuthResult> task) {
            if (task.isSuccessful()){
                firebaseUserMutableLiveData.postValue(auth.getCurrentUser());

                // Add user to realtime database
                FirebaseUser user = auth.getCurrentUser();

                dbRef.child("Users").child(user.getUid()).setValue(new User(email, username, department));
            }
            else{
                Toast.makeText(application, task.getException().getMessage(), Toast.LENGTH_SHORT).show();
            }
        }
    });
}

既然你有了主要的想法,让我们继续我的问题。就像 AuthRepository 一样,我有一个 MainRepository 作为变量添加到 MainViewModel 中,它是负责第二个活动中 4 个片段的 ViewModel。

无论我尝试了什么,我都无法检索相应用户的用户对象并将该对象分配给 MainRepository 类中的用户变量。

问题不在于检索数据,因为 “IN LISTENER:” Toast 在实时数据库中显示正确的用户对象

但是 "OUT LISTENER: ""FINAL: " Toast 显示了在侦听器之外初始化的 User 对象。我不知道为什么,但侦听器中的用户对象似乎是类中用户对象的副本,即使它们共享相同的哈希码,如果我没有在 firebase 中为用户对象分配用户对象。

尽管进行了长时间的搜索,但我无法从内部类访问外部类的“真实”对象“不是副本”。即使我似乎正在访问和调用外部对象的方法,它们也不会持续存在于侦听器之外。

这里有什么问题,我能做些什么来解决它?如果无法解决,我应该怎么做呢?

不同的输出

Toast.makeText(application, "IN LISTENER: "+ user.hashCode() + user.getDepartment(), Toast.LENGTH_SHORT).show();

相同的输出

Toast.makeText(application, "OUT LISTENER: "+ user.hashCode() + user.getDepartment(), Toast.LENGTH_SHORT).show();

Toast.makeText(application, "FINAL: "+ user.hashCode() + user.getDepartment(), Toast.LENGTH_SHORT).show();

public class MainRepository {
private Application application;
private FirebaseAuth auth;
private DatabaseReference dbRef;
private MutableLiveData<User> userMutableLiveData;
private User user;

public MainRepository(Application application) {
    this.application = application;
    auth = FirebaseAuth.getInstance();
    dbRef = FirebaseDatabase.getInstance().getReference();
    getUser();
    Toast.makeText(application, "FINAL: " + user.hashCode() + user.getDepartment(), Toast.LENGTH_SHORT).show();
}

class ListenerInner implements ValueEventListener {
    MainRepository mainRepository;

    ListenerInner(MainRepository mainRepository) {
        this.mainRepository = mainRepository;
    }
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) {
        mainRepository.setUser(snapshot.getValue(User.class));
        Toast.makeText(application, "IN LISTENER: "+ user.hashCode() + user.getDepartment(), Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onCancelled(@NonNull DatabaseError error) {
        Toast.makeText(application, "Error: " + error.getMessage(), Toast.LENGTH_SHORT).show();
    }
}
public void getUser() {
    setUser(new User("aaa", "bbb", "ccc"));
    dbRef.child("Users").child(auth.getCurrentUser().getUid()).addListenerForSingleValueEvent(new ListenerInner(this));

    Toast.makeText(application, "OUT LISTENER: " + user.hashCode() + user.getDepartment(), Toast.LENGTH_SHORT).show();
}

private void setUser(User user) {
    this.user = user;
}

}

【问题讨论】:

    标签: java android firebase firebase-realtime-database inner-classes


    【解决方案1】:

    问题不在于在哪里从数据库中访问数据,而是何时访问它。

    数据是从 Firebase(和大多数云 API)异步加载的,因为获取它可能需要一些时间。在加载数据时,您的主代码/线程继续执行。然后当代码可用时,使用该数据调用侦听器上的 onDataChange

    这意味着主线程上的任何代码(例如Toast.makeText(application, "OUT LISTENER: " + user.hashCode() + user.getDepartment(), Toast.LENGTH_SHORT).show())都将在onDataChange 被调用并完成其mainRepository.setUser(snapshot.getValue(User.class)) 之前运行。验证这一点的最简单方法是在这些行上设置断点并在调试器中运行代码,或者通过记录一些输出并在 logcat 中检查其输出的顺序。

    解决方案总是相同的:任何需要数据库数据的代码都需要在 onDataChange 内,从那里调用,或者以其他方式同步。

    有关此问题的一个很好的示例以及使用这些方法,请参阅:

    【讨论】:

    • 非常感谢我是“异步”概念的新手。对于解决方案,我声明了一个 MutableLiveData,它在我的侦听器的 onDataChange 方法中更新。然后我在 Fragments 中使用 LiveData 的 onChanged 方法来更新相应的视图。一切似乎都运行正常。
    • 哦,是的,MutableLiveData 听起来是个不错的解决方案。 ?
    猜你喜欢
    • 2010-12-21
    • 1970-01-01
    • 2021-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-28
    • 1970-01-01
    相关资源
    最近更新 更多