I found that my ListView is not updated when the app is run because the adapter is set before the Firebase query occurs.
First Question: Is there anyway to set a listener for query completion? This way I can set the adapter
there instead. I know some Firebase methods auto-generate onComplete()
/onSuccess()
listeners.
For debugging purposes I can trigger an update to the ListView by re-entering onResume()
. This is where I receive an error message:
The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(16908298, class android.widget.ListView) with Adapter(class android.widget.ArrayAdapter)]
To my understanding this error means I cannot add items to my ArrayList
"usernames
" inside the onChildAdded()
method if I use usernames
in my ArrayAdapter
.
Second Question: How else can I store the values returned from my Firebase query and use those to ultimately populate a ListView without directly changing its contents from a "background thread"?
My attempt:
public class EditFriendsActivity extends AppCompatActivity {
protected ArrayList<String> usernames = new ArrayList<>();
@Override
protected void onResume() {
super.onResume();
Firebase usernameRef = ref.child("users");
Query queryRef = usernameRef.orderByKey();
queryRef.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String username = (String) dataSnapshot.child("username").getValue();
usernames.add(username);
Log.v(TAG, usernames + "");
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
Log.v(TAG, "Inside ChildChanged");
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.v(TAG, "Inside ChildRemoved");
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
Log.v(TAG, "Inside ChildMoved");
}
@Override
public void onCancelled(FirebaseError firebaseError) {
Log.e(TAG, firebaseError.getMessage());
AlertDialog.Builder builder = new AlertDialog.Builder(EditFriendsActivity.this);
builder.setTitle(R.string.error_title)
.setMessage(firebaseError.getMessage())
.setPositiveButton(android.R.string.ok, null);
AlertDialog dialog = builder.create();
dialog.show();
}
});
// Array adapter
ArrayAdapter<String> adapter = new ArrayAdapter<>(
EditFriendsActivity.this,
android.R.layout.simple_list_item_multiple_choice,
usernames);
mFriendsList.setAdapter(adapter);
}
}
Updated Code: Fixed typo in listener from marked answer and cleared list each time.
Firebase userRef = ref.child("users");
userRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
usernames.clear(); // Clear list before updating
for (DataSnapshot child : dataSnapshot.getChildren()) {
String username = (String) child.child("username").getValue();
usernames.add(username);
Log.v(TAG, usernames + "");
}
Follow Up Question Here