tccpg288 tccpg288 - 6 months ago 37
Android Question

Dynamic ListView Item Not Populating XML

I have a dynamic ListView that I am updating based on a Firebase listener. I initially populate the ListView, and then as items are added to Firebase I call notifySetDataChanged() to update the ListView.

Here is the initialization of the ListView:

mUpdateRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
setImage(dataSnapshot);
setQuestion(dataSnapshot);
createInitialCommentArray(dataSnapshot);
mNumberOfCommentsAtPoll = (int) dataSnapshot.child(COMMENTS_LABEL).getChildrenCount();
for (int i = 0; i < mNumberOfCommentsAtPoll; i++){
String commentID = (String) dataSnapshot.child(COMMENTS_LABEL).child(mCommentIDArrayList.get(i)).child("COMMENT").getValue();
Log.v("COMMENT_ID", "The comment ID is " + commentID);
String userID = (String) dataSnapshot.child(COMMENTS_LABEL).child(mCommentIDArrayList.get(i)).child("USER_ID").getValue();
Log.v("USER_ID", "The user ID is " + userID);
mCommentArrayList.add(i, new Comments(mUserAvatar, userID, commentID));
mCommentAdapter.notifyDataSetChanged();
}

}


Here is the CommentArray I am creating and using to populate items in the ListView:

private void createInitialCommentArray(DataSnapshot dataSnapshot) {
for (DataSnapshot s : dataSnapshot.child(COMMENTS_LABEL).getChildren()) {
mCommentIDArrayList.add(s.getKey());
Log.v("COMMENT_ARRAY", "The comment array is " + s.getKey());
}
}


Here is where I add a new comment based on a ChildEventListener:

@Override
protected void onStart() {
super.onStart();
mUpdateComments = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
int updatedNumberOfCommentsAtPoll = (int) dataSnapshot.child(COMMENTS_LABEL).getChildrenCount();
String pollCount =(String.valueOf(updatedNumberOfCommentsAtPoll));
String commentID = (String) dataSnapshot.child(COMMENTS_LABEL).child(pollCount).child("COMMENT").getValue();
String userID = (String) dataSnapshot.child(COMMENTS_LABEL).child(pollCount).child("USER_ID").getValue();
mCommentArrayList.add(new Comments(mUserAvatar, userID, commentID));
mCommentAdapter.notifyDataSetChanged();
}

@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {

}

@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {

}

@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {

}

@Override
public void onCancelled(FirebaseError firebaseError) {

}
};
mUpdateRef.addChildEventListener(mUpdateComments);

}

@Override
protected void onStop() {
super.onStop();
mUpdateRef.removeEventListener(mUpdateComments);
}


Here is the Adapter Class:

public class ListAdapter extends ArrayAdapter<Comments> {

public ListAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
}

public ListAdapter(Context context, int resource, List<Comments> items) {
super(context, resource, items);
}

@Override
public int getCount() {
return mNumberOfCommentsAtPoll;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

View v = convertView;

if (v == null) {
LayoutInflater vi;
vi = LayoutInflater.from(getContext());
v = vi.inflate(R.layout.individual_comment, null);
}

Comments p = getItem(position);

if (p != null) {
TextView userID = (TextView) v.findViewById(R.id.user_ID);
TextView userComment = (TextView) v.findViewById(R.id.user_comment);

if (userID != null) {
userID.setText(p.getUserID());
}

if (userComment != null) {
userComment.setText(p.getUserComment());
}
}


return v;
}

}


Here is where the data gets added to Firebase after clicking the FAB:

fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
HashMap<String, Object> commentMap = new HashMap<String, Object>();
commentMap.put("USER_ID", mBaseRef.getAuth().getUid());
commentMap.put("COMMENT", mUserComment.getText().toString());
mUpdateRef.child(COMMENTS_LABEL).push().updateChildren(commentMap);

hideKeyboard(view);
mUserComment.setText("");
Toast.makeText(getApplicationContext(),R.string.comment_added, Toast.LENGTH_LONG).show();
}
});


Unfortunately, the ListView is not populating the appropriate TextViews on my device, I am not sure why:

enter image description here

Answer

You have used addListenerForSingleValueEvent() which will be invoked only once and will get unregistered after got invoked. So when the data gets changed in the firebase database in case you change it (as you are doing it in fab onclick), you'll not get the callback for data changed as your listener is no longer registered.

For your task, you either need to use addValueEventListener() or implement Child event listeners. And yes, don't forget to remove those when you no longer need it. Your onChildAdded() has issues.

String commentID = (String) dataSnapshot.child(COMMENTS_LABEL).child(pollCount).child("COMMENT").getValue();
String userID = (String) dataSnapshot.child(COMMENTS_LABEL).child(pollCount).child("USER_ID").getValue();

Above statements will not behave as you expect them to do so. As per your fab fab.setOnClickListener(), you are generating random unique keys as a child of COMMENTS_LABEL and that key contains your user_id and comment.

But you are trying to fetch the user_id and comment from the child of COMMENTS_LABEL using index 0,1,2,etc. which will never fetch the exact values you saved as you don't know what is the unique id. You need to change onChildAdded() somewhat like this-

@Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) {

            String commentID = (String) dataSnapshot.child(COMMENTS_LABEL).child(dataSnapshot.getKey()).child("COMMENT").getValue();
            String userID = (String) dataSnapshot.child(COMMENTS_LABEL).child(dataSnapshot.getKey()).child("USER_ID").getValue();
            mCommentArrayList.add(new Comments(mUserAvatar, userID, commentID));
            mCommentAdapter.notifyDataSetChanged();
        }
Comments