使用Firebase更新ArrayAdapter ChildEventListener()

时间:2016-03-01 21:55:29

标签: android listview firebase android-arrayadapter

我的Firebase数据库结构如此:

   {
  "reviews" : {
    "Star Trek Into Darkness" : {
      "j" : {
        "major" : "NONE",
        "rating" : 3.0,
        "username" : "j"
      }
    },
    "Star Wars" : {
      "badabing" : {
        "major" : "Computer Science",
        "rating" : 3.5,
        "username" : "badabing"
      },
      "j" : {
        "major" : "NONE",
        "rating" : 5.0,
        "username" : "j"
      }
    },
    "Star Wars: The Clone Wars" : {
      "j" : {
        "major" : "NONE",
        "rating" : 3.0,
        "username" : "j"
      }
    },
    "Star Wars: The Force Awakens" : {
      "badabing" : {
        "major" : "Computer Science",
        "rating" : 5.0,
        "username" : "badabing"
      },
      "j" : {
        "major" : "NONE",
        "rating" : 3.0,
        "username" : "j"
      }
    }
  }

reviews下有电影,每个movie都有usernamemajorrating。我有兴趣获得这三个孩子的PER用户名(三个孩子的父母)。应该发生的是当用户观看"电影细节"我的应用程序的屏幕 - 他们将看到其他用户留下的评论。很简单。

我在更新自定义ReviewAdapter方面遇到了很大困难。目前,如果我们点击一​​部没有评论的电影 - 我可以添加它们没问题。我甚至可以对我留下的评论进行编辑。唯一的问题是提交的评论提交了两篇评论 - 所以我最终会留下一份副本,直到我离开活动并回来。

My issue can be seen in this recording here. (No sound)

我怀疑它与我使用Firebase的childEventListener()的方式有关,但我不知道在这个问题上花了4小时+之后会发生什么变化。

MovieDetailActivity.java

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_movie_detail);
        ButterKnife.bind(this);

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

        Intent intent = getIntent();
        Bundle bundle = intent.getExtras();

        if (bundle != null) {
            mMovieTitle = (String) bundle.get("title");
            mTempMovieTitle.setText(mMovieTitle);
        }

        setupReviews(); //calling it here
    }


public void leaveReview() {
        //get current username
        final String currentUser = SessionManager.getInstance(MovieDetailActivity.this).getLoggedInUsername();
        final MaterialDialog reviewDialog = new MaterialDialog.Builder(MovieDetailActivity.this)
                .title(leaveReviewTitle)
                .customView(R.layout.rating_movie_dialog, true)
                .theme(Theme.DARK)
                .positiveText(save)
                .negativeText(cancel)
                .onPositive(new MaterialDialog.SingleButtonCallback() {
                    @Override
                    public void onClick(@NonNull MaterialDialog reviewDialog, @NonNull DialogAction which) {
                        final RatingBar ratingBar = ButterKnife.findById(reviewDialog, R.id.rating_bar);
                        final double rating = ratingBar.getRating(); //get the rating

                        /*Get Major from Firebase, and also store the review while we're at it*/
                        mUserRef.child(currentUser).addListenerForSingleValueEvent(new ValueEventListener() {
                            @Override
                            public void onDataChange(DataSnapshot dataSnapshot) {
                                String major = dataSnapshot.child("major").getValue(String.class);
                                final Firebase reviewRef = mReviewRef.child(StringHelper.reviewHelper(mMovieTitle, currentUser));
                                reviewRef.child("username").setValue(currentUser);
                                reviewRef.child("major").setValue(major);
                                reviewRef.child("rating").setValue(rating);
                                setupReviews(); //and here
                            }
                            @Override
                            public void onCancelled(FirebaseError firebaseError) {
                            }
                        });
                    }
                }).build();
        //Leave review as {current_username}
        TextView reviewee = ButterKnife.findById(reviewDialog, R.id.reviewee);
        reviewee.append(" " + (Html.fromHtml("<b>" + currentUser + "</b>"))); //bold the username text
        reviewDialog.show();
    }

    /**
     * *ATTEMPTS* to add and update the reviews list per each movie. It's hacky and I hate it.
     */
    private void setupReviews() {
        mReviewRef.child(mMovieTitle).addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String previousChildKey) {
                ArrayList<String> usernames = new ArrayList<>();
                ArrayList<String> majors = new ArrayList<>();
                ArrayList<Double> ratings = new ArrayList<>();
                ArrayList<Review> reviews = new ArrayList<>();

                //iterate through all of the reviews for the movie
                for (DataSnapshot child : dataSnapshot.getChildren()) {
                    switch(child.getKey()) {
                        case ("username"):
                            usernames.add(child.getValue(String.class));
                            break;
                        case ("major"):
                            majors.add(child.getValue(String.class));
                            break;
                        case ("rating"):
                            ratings.add(child.getValue(Double.class));
                            break;
                    }
                }

                if (!usernames.isEmpty()) { //only want to iterate if we're rating a movie that already has reviews
                    for (int i = 0; i < usernames.size(); ++i) {
                        try {
                            reviews.add(new Review(usernames.get(i), majors.get(i), ratings.get(i)));
                        } catch (IndexOutOfBoundsException ioobe) {
                        }
                    }
                }

                if (mReviewAdapter == null) {
                    mReviewAdapter = new ReviewAdapter(MovieDetailActivity.this,
                            R.layout.review_list_item, reviews);
                    mMovieReviewsList.setAdapter(mReviewAdapter);
                } else {
                    try {
                        mReviewAdapter.addAll(reviews);
                        mMovieReviewsList.setAdapter(mReviewAdapter);
                        mReviewAdapter.notifyDataSetChanged();
                    } catch (NullPointerException npe) {
                    }
                }
            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String previousChildKey) {
                ArrayList<String> usernames = new ArrayList<>();
                ArrayList<String> majors = new ArrayList<>();
                ArrayList<Double> ratings = new ArrayList<>();
                ArrayList<Review> reviews = new ArrayList<>();

                //iterate through all of the reviews for the movie
                for (DataSnapshot child : dataSnapshot.getChildren()) {
                    switch(child.getKey()) {
                        case ("username"):
                            usernames.add(child.getValue(String.class));
                            System.out.println("username " + child.getValue(String.class));
                            break;
                        case ("major"):
                            majors.add(child.getValue(String.class));
                            System.out.println("major " + child.getValue(String.class));
                            break;
                        case ("rating"):
                            ratings.add(child.getValue(Double.class));
                            break;
                    }
                }
                if (mReviewAdapter != null) {
                    mReviewAdapter.clear();
                }


                if (!usernames.isEmpty()) {
                    for (int i = 0; i < usernames.size(); ++i) {
                        try { //I hate that checking if Usernames != empty isn't enough, and this is
                            //the only way I could get it to work...
                            reviews.add(new Review(usernames.get(i), majors.get(i), ratings.get(i)));
                        } catch (IndexOutOfBoundsException ioobe) {
                        }
                    }
                }

                if (mReviewAdapter == null) {
                    mReviewAdapter = new ReviewAdapter(MovieDetailActivity.this,
                            R.layout.review_list_item, reviews);
                    mMovieReviewsList.setAdapter(mReviewAdapter);
                } else {
                    try {
                        mReviewAdapter.addAll(reviews); //this might break it
                        mMovieReviewsList.setAdapter(mReviewAdapter);
                        mReviewAdapter.notifyDataSetChanged();
                    } catch (NullPointerException npe) {
                    }
                }
            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {
            }
            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String previousChildKey) {
            }

            @Override
            public void onCancelled(FirebaseError firebaseError) {
            }
        });
    }

1 个答案:

答案 0 :(得分:1)

您需要使用Push方法才能拥有自己的唯一键。您正在使用具有已登录用户的用户名的密钥。你需要做这样的事情。

    {
  "reviews" : {
    "Star Trek Into Darkness" : {
      "-K3dksosdfify" : {
        "major" : "NONE",
        "rating" : 3.0,
        "username" : "j"
      }
    },
    "Star Wars" : {
      "-K3dksosdfify2" : {
        "major" : "Computer Science",
        "rating" : 3.5,
        "username" : "badabing"
      },
      "-K3dksosdfify4" : {
        "major" : "NONE",
        "rating" : 5.0,
        "username" : "j"
      }
    },
    "Star Wars: The Clone Wars" : {
      "-K3dksosdfify10" : {
        "major" : "NONE",
        "rating" : 3.0,
        "username" : "j"
      }
    },
    "Star Wars: The Force Awakens" : {
      "-K3dksosdfify11" : {
        "major" : "Computer Science",
        "rating" : 5.0,
        "username" : "badabing"
      },
      "-K3dksosdfify123" : {
        "major" : "NONE",
        "rating" : 3.0,
        "username" : "j"
      }
    }
  }

Dashes是FireBase生成的。 Check the push method in the Official Document

现在每次使用推送。它将生成一个唯一键,因此其他评级的属性不会受到干扰。

这样的事情。

Firebase ref = new Firebase(yourURLtoReviews);
ref.child(SELECTEDMOVIES);

Map<String, String> post1 = new HashMap<String, String>();
post1.put("major", "gracehop");
post1.put("rating", "3.0");
post1.put("username", "Hwoarang");

ref.push().setValue(post1);

现在你不再需要关心键了。你所要做的就是    ref.onChildAdded blah blah blah,it for for for循环,你已经完成了。