Android:在服务首次初始化期间从 Firebase 获取 Pojo 列表 Class

Android: Get a Pojo List from Firebase during the first initialization from the Service Class

我尝试从 Firebase 获取我所有“示例”Pojo 的列表。我的服务 Class 是一个 Singelton,在构造函数中我调用方法初始化,它调用方法 readAll()。那么为什么“readAll()”不能正常工作呢?它在 return 之后很长时间运行 onDataChange,因此它 return 为空而不是 Pojo 列表。

Service

public class Service {
    private static volatile Service instance = null;
    private List<Example> exampleList= new LinkedList<>();
    private ExampleDao exampleDao = new ExampleDao();


    public void initialize(){
       exampleList= exampleDao .readAll();
    }

   private Service(){
        initialize();
    }

    public static synchronized Service getInstance(){
        if(instance==null)
            instance = new Service();
        return instance;
    }
}

DAO

public class ExampleDao implements ExampleDao<Example> {
    private FirebaseDatabase database = FirebaseDatabase.getInstance();
    DatabaseReference myRef = database.getReference("example");
    private List<Example> pojoList=  null;


    @Override
    public List<Example> readAll() {
        // Read from the database

        myRef.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                    pojoList= new LinkedList<>();
                for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
                    pojoList.add(postSnapshot.getValue(Example.class));
                }




            }

            @Override
            public void onCancelled(DatabaseError error) {
                // Failed to read value
                Log.w(TAG, "Failed to read value.", error.toException());
            }
        });


        return pojoList;
    }
} 

数据从 Firebase 异步加载。

由于数据从服务器返回可能需要相当长的时间,并且在此期间阻止应用程序会导致“应用程序无响应”对话框,Firebase 允许您的应用程序代码在加载时继续数据库。然后,当数据从服务器返回时,Firebase 客户端使用该数据调用您的 onDataChange 方法。

查看此信息的最简单方法是在您的代码中添加一些日志语句:

public List<Example> readAll() {
    Log.i(TAG, "Before attaching listener");
    myRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            Log.i(TAG, "Inside onDataChange");
        }

        @Override
        public void onCancelled(DatabaseError error) {
            Log.w(TAG, "Failed to read value.", error.toException());
        }
    });
    Log.i(TAG, "After attaching listener");
}

如果你运行这个代码输出是:

Before attaching listener

After attaching listener

Inside onDataChange

这可能不是您期望的顺序。但它完美地解释了为什么 pojoList 当你 return 时它是空的:数据还没有被加载。

无法更改此行为:异步 API 是针对现代 Web API 编写应用程序所固有的。我发现处理这种行为的最佳方法是重新构建我的解决方案。我没有考虑“首先读取所有数据,然后对其进行处理”,而是将其视为“开始加载所有数据。每当读取数据时,对其进行处理。”

实际上,这意味着需要从数据库中获取数据的所有代码都需要在 方法 中(从中调用)onDataChange 方法。所以说你想打印加载的数据,你会这样做:

public void readAll() {
    myRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            pojoList= new LinkedList<>();
            for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
                pojoList.add(postSnapshot.getValue(Example.class));
            }
            Log.i(TAG, pojoList);
        }

        @Override
        public void onCancelled(DatabaseError error) {
            Log.w(TAG, "Failed to read value.", error.toException());
        }
    });
}

现在这会使您的代码不太灵活,因为您正在将日志记录 编码为 onDataChange。所以你也可以创建自己的回调接口,如我在这里的回答所示:。 这个话题让很多 Firebase 新手感到困惑。我强烈建议您查看从那里链接的一些以前的答案。