gpt4 book ai didi

Android - Firebase - getChildrenCount() 方法问题

转载 作者:行者123 更新时间:2023-11-30 00:57:13 26 4
gpt4 key购买 nike

目前,我正在构建一个使用 Firebase 数据库的 Android 应用程序。

在我的代码中,我试图获取我的 Firebase 数据库特定路径中的子项数量。定义了 Firebase 特定路径的引用后,我创建了一个监听器以获取 DataSnapshot,然后调用 getChildrenCount()。

之后,我想在 FOR 循环中使用这个结果。但是,代码不起作用。

它似乎首先执行了 FOR 循环(我意识到因为 Log.v("NUM_OF_PRODUCTS",numOfProducts+"") 输出 0 而不是 3)并且 Listener 在之后执行,而在代码中,监听器代码在前,然后是 FOR-Loop 代码。

我的部分代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_product_selection);

selected_cat = getIntent().getExtras().getString("pass_selected_cat");
listView = (ListView) findViewById(R.id.listView);
final ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, arrayList);
listView.setAdapter(adapter);
fbdatabase = FirebaseDatabase.getInstance();
fbref_products = fbdatabase.getReference("PRODUCTS/SM_0/" + selected_cat);

//Listener for getting numOfProducts.
fbref_products.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
numOfProducts = (int) dataSnapshot.getChildrenCount();
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});

//Print numOfProducts before FOR-Loop being executed.
Log.v("NUM_OF_PRODUCTS",numOfProducts+"");


//FOR-Loop
for (int i = 0; i < numOfProducts; i++) {
String str = i + "";
DatabaseReference product_ref = fbref_products.child(str);

product_ref.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, Object> map = (Map<String, Object>) dataSnapshot.getValue();
String productName = (String) map.get("productName");

arrayList.add(productName);
adapter.notifyDataSetChanged();
}

@Override
public void onCancelled(DatabaseError databaseError) {
//textView.setText("The read failed: " + databaseError.getMessage());
}
});
}

如果不是变量 numOfProducts,我的代码工作正常,我们有一个特定的数字。

谁能帮帮我??

最佳答案

来自 Firebase 数据库的数据是异步加载的。当您运行 for 循环时,它还没有加载。

如果在代码中放置一些日志语句,最容易看到这一点:

System.out.println("Before attaching listener");
fbref_products.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
System.out.println("In onDataChange");

}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
System.out.println("After attaching listener");

当你运行它时,输出将是:

Before attaching listener

After attaching listener

In onDataChange

这可能不是您期望的顺序。但这完美地解释了为什么当您开始循环时 numOfProducts 仍然是 0:数据只是还没有从 Firebase 加载。

几乎每个开发人员的最初 react 都是“我不想要这个。我如何让它以正确的顺序执行?”这是一种自然 react ,但在针对 Web/云 API 进行编程时,您必须抑制这种 react 才能到达任何地方。我还建议在这里阅读我的回答:Setting Singleton property value in Firebase Listener

解决方案是将您的解决方案从“首先我将获取产品数量,然后我将遍历产品”重新定义为“每当我获取产品时,我将遍历它们”。

在代码中是:

fbref_products.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
numOfProducts = (int) dataSnapshot.getChildrenCount();
for (int i = 0; i < numOfProducts; i++) {
String str = i + "";
DatabaseReference product_ref = fbref_products.child(str);

product_ref.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, Object> map = (Map<String, Object>) dataSnapshot.getValue();
String productName = (String) map.get("productName");

arrayList.add(productName);
adapter.notifyDataSetChanged();
}

@Override
public void onCancelled(DatabaseError databaseError) {
//textView.setText("The read failed: " + databaseError.getMessage());
}
});
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});

除了整个处理异步事件之外,您还可以显着简化这段代码:

fbref_products.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot productSnapshot: dataSnapshot.getChildren()) {
String productName = productSnapshot.child("productName").getValue(String.class);
arrayList.add(productName);
adapter.notifyDataSetChanged();
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});

变化:

  1. 这只使用一个监听器。不需要第二个监听器,因为检索节点也已经检索了该节点下的所有数据。您可以遍历子节点。
  2. 这不是先提取HashMap,而是直接从子快照中读取数据。

您应该考虑的另一项更改是保留一个单独的产品名称列表。您现在检索所有产品数据以显示名称列表,这是一种浪费。如果您保留一个仅包含产品名称的单独列表,则可以改为加载它。在使用 Firebase(或几乎任何 NoSQL 数据库)时,您会发现一个共同的主题:按照您在屏幕上显示数据的方式对数据库中的数据进行建模。

关于Android - Firebase - getChildrenCount() 方法问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39941542/

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