检索ArrayList< Object>来自FireBase内部类 [英] Retrieving ArrayList<Object> from FireBase inner class

查看:95
本文介绍了检索ArrayList< Object>来自FireBase内部类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我能找到的所有代码示例显示如何获得一个值,然后立即在Firebase的ValueEventListener内部类中打印它。我想获取值并将它们存储在一个数组中,以备后用。

我试图做的是当用户点击高分按钮时,客户端获得当前然后将这个列表发送给高级的班级。



更新:现在我已经能够检索数据,但是有一个行为使我非常困惑。如果用户点击高分按钮,分数列表被填充,高分类正确显示10个元素。如果我退出记分牌并再次输入,现在将显示所有分数两次(可以理解,因为我只是添加到相同的列表中)。但任何调用scores.clear()或分数=新的ArrayList();在两次点击之间,结果即使在第二次点击之后,分数也是空的(我假设填充分数,然后清空它并重新填充它将在那里留下10个项目)这种行为是我认为我的分数数组在第一次发布时从未被填充的原因在这里,因为我不想重复值,因此我在load函数中调用了scores.clear()。如果有人能够解释为什么会发生这种情况,那就太好了。

  public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
ArrayList< Score>分数;
Firebase myFirebase;

@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Firebase.setAndroidContext(this);
myFirebase =新的Firebase(FirebaseURL);
scores = new ArrayList< Score>();
loadScoresFromFireBase();

public void loadScoresFromFireBase(){
String entry =;
for(int i = 0; i <10; i ++){
entry =Name_+ i;
myFirebase.child(users)。child(entry).addValueEventListener(new ValueEventListener(){
@Override
public void onDataChange(DataSnapshot snapshot){
// getValue正确地返回一个Score对象
scores.add(snapshot.getValue(Score.class));
}
$ b @Override
public void onCancelled(FirebaseError firebaseError){

}
});


$ @Override
public void onItemClick(AdapterView<> parent,View view,int position,long id){
/ / ....
if(id == 2){
Intent intent = new Intent(getApplicationContext(),ScoreBoard.class);
Bundle bundle = new Bundle();
//调用scores.clear()在这里将得分数组留空,即使之后调用loadscores。
loadScoresFromFireBase();
Collections.sort(分数);
bundle.putSerializable(players,scores);
intent.putExtra(players,bundle);
startActivityForResult(intent,0);




$ b

解决

  loadScoresFromFireBase();方法


Collections.sort(分数);

当您调用 loadScoresFromFireBase()拼写 Firebase btw),程序开始同步服务器的分数。加载这些数据需要一些时间。 Firebase不会让您的程序等待(这将是一个糟糕的用户体验),而是让您传入 ValueEventListener ,然后在数据可用时调用它。但是在第一个数据被加载之前,你直接调用 Collections.sort(scores)

<您可以通过添加一些日志语句来轻松看到这一点:

  public void loadScoresFromFireBase(){
String entry =;
for(int i = 0; i <10; i ++){
entry =Name_+ i;
myFirebase.child(users)。child(entry).addValueEventListener(new ValueEventListener(){
public void onDataChange(DataSnapshot snapshot){
System.out.println(Add score );
scores.add(snapshot.getValue(Score.class));
}
public void onCancelled(FirebaseError firebaseError){}
});


$ b public void onItemClick(AdapterView<> parent,View view,int position,long id){
// ....
if(id == 2){
Intent intent = new Intent(getApplicationContext(),ScoreBoard.class);
Bundle bundle = new Bundle();
System.out.println(在调用loadScores之前);
loadScoresFromFireBase();
System.out.println(调用loadScores之后);
Collections.sort(分数);
System.out.println(排序分数后);

这些日志语句的输出将是:


在调用loadScores之前



调用loadScores之后



/ p>

向数组添加分数

这可能不是您所期望的。但是当你处理异步/事件驱动的代码时,这是完全正常的,就像在现代互联网编程中常见的那样。

最直接的解决方案是将代码需要分数到加载它们的函数中:

pre $ public void loadScoresFromFireBase(){
String entry =;
for(int i = 0; i <10; i ++){
entry =Name_+ i;
myFirebase.child(users)。child(entry).addValueEventListener(new ValueEventListener(){$ b $ public void onDataChange(DataSnapshot snapshot){
scores.add(snapshot.getValue(Score .class));
Collections.sort(scores);
Intent intent = new Intent(getApplicationContext(),ScoreBoard.class);
Bundle bundle = new Bundle();
bundle.putSerializable(players,scores);
intent.putExtra(players,bundle);
startActivityForResult(intent,0);
}
public void onCancelled (FirebaseError firebaseError){}
});


$ b public void onItemClick(AdapterView<> parent,View view,int position,long id){
// ....
if(id == 2){
loadScoresFromFireBase();

另见前面我写的答案:在Firebase Listener中设置Singleton属性值

对同样的问题,这些很好的答案:



虽然这些是关于JavaScript的,他们处理完全相同的问题。


I've been looking at the firebase documentation and tried to make firebase work with an android app I'm building.

All the code examples I could find show how to get a value, then immediately print it within the firebase ValueEventListener inner class. I would like to get the values and store them in an array for later use.

What I try to do is when a user clicks the highscore button the client gets the current scoreboard from firebase, and sends that list to the highscoreboard class.

UPDATE: I have been able to retrieve the data now but there is a behavior that confuses me greatly. If the user clicks the highscorebutton the scores list gets populated and highscore class is correctly showing 10 elements. If I exit the scoreboard and enter it again it will now show all scores twice (understandably so, as I am just adding to the same list). But any calls to scores.clear() or scores = new ArrayList(); between the two clicks results in scores being empty even after the second click (I assumed that populating scores, then emptying it and repopulating it would leave 10 items in there) This behavior was the reason I thought my scores array never got populate when first posting here as I had a scores.clear() call inside the load function since I didn't want to duplicate values. If anyone is able to explain why this happens that would be fantastic.

public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
ArrayList<Score> scores;
Firebase myFirebase;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Firebase.setAndroidContext(this);
    myFirebase = new Firebase(FirebaseURL);
    scores = new ArrayList<Score>();
    loadScoresFromFireBase();
}
public void loadScoresFromFireBase() {
    String entry = "";
    for (int i = 0; i < 10; i++) {
        entry = "Name_" + i;
        myFirebase.child("users").child(entry).addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot snapshot) {
                //getValue correctly returns a Score object
                scores.add(snapshot.getValue(Score.class));
            }

            @Override
            public void onCancelled(FirebaseError firebaseError) {

            }
        });

    }
}
 @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
   //....
    if ( id == 2) {
        Intent intent = new Intent(getApplicationContext(), ScoreBoard.class);
        Bundle bundle = new Bundle();
        //calling scores.clear() here leaves the scores array empty even though loadscores is called afterwards.
        loadScoresFromFireBase();
        Collections.sort(scores);
        bundle.putSerializable("players", scores);
        intent.putExtra("players", bundle);
        startActivityForResult(intent, 0);

    }
}
}

解决方案

You're falling for the classic asynchronous trap:

loadScoresFromFireBase();
Collections.sort(scores);

When you call loadScoresFromFireBase() (it's spelled Firebase btw), the program starts synchronizing the scores from the server. Loading this data takes some time. Instead of making your program wait (which would be a bad user experience), Firebase makes you pass in a ValueEventListener that it then calls when the data is available. But you're calling Collections.sort(scores) straight away, before the (first) data has been loaded.

You can most easily see this by adding a few log statements:

public void loadScoresFromFireBase() {
    String entry = "";
    for (int i = 0; i < 10; i++) {
        entry = "Name_" + i;
        myFirebase.child("users").child(entry).addValueEventListener(new ValueEventListener() {
            public void onDataChange(DataSnapshot snapshot) {
                System.out.println("Adding score to array");
                scores.add(snapshot.getValue(Score.class));
            }
            public void onCancelled(FirebaseError firebaseError) { }
        });

    }
}
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    //....
    if (id == 2) {
        Intent intent = new Intent(getApplicationContext(), ScoreBoard.class);
        Bundle bundle = new Bundle();
        System.out.println("Before calling loadScores");
        loadScoresFromFireBase();
        System.out.println("After calling loadScores");
        Collections.sort(scores);
        System.out.println("After sorting scores");

The output of these log statements will be:

Before calling loadScores

After calling loadScores

After sorting scores

Adding score to array

That is probably not what you expected. But it is completely normal when you're dealing with asynchronous/event driven code, like is common in modern internet programming.

The most direct solution is to move the code that needs the scores into the function that loads them:

public void loadScoresFromFireBase() {
    String entry = "";
    for (int i = 0; i < 10; i++) {
        entry = "Name_" + i;
        myFirebase.child("users").child(entry).addValueEventListener(new ValueEventListener() {
            public void onDataChange(DataSnapshot snapshot) {
                scores.add(snapshot.getValue(Score.class));
                Collections.sort(scores);
                Intent intent = new Intent(getApplicationContext(), ScoreBoard.class);
                Bundle bundle = new Bundle();
                bundle.putSerializable("players", scores);
                intent.putExtra("players", bundle);
                startActivityForResult(intent, 0);
            }
            public void onCancelled(FirebaseError firebaseError) { }
        });

    }
}
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    //....
    if (id == 2) {
        loadScoresFromFireBase();

Also see this answer I wrote a while ago: Setting Singleton property value in Firebase Listener

As well as these great answers on the same problem:

Although these are about JavaScript, they deal with the exact same problem.

这篇关于检索ArrayList&lt; Object&gt;来自FireBase内部类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆