public void readUniversity(){
ChildEventListener uniListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
//Log.d(LOG_TAG, dataSnapshot.getKey());
University uni = dataSnapshot.getValue(University.class);
universitieslist.add(uni); //Adding to an ArrayList of type University
//Log.d(LOG_TAG, universitieslist.size()+"is the size");
arrayofUniversities.add(uni.getName()); //Adding name of University to list
//Log.d(LOG_TAG, adapter.getCount() + " items");
//Log.d(LOG_TAG, arrayofUniversities.size()+" is the size");
adapter.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(DatabaseError databaseError) {
}
};
DatabaseReference uniReference = database.getReference("note-retrieve/Universities");
uniReference.addChildEventListener(uniListener);
}
The code is pretty much self explanatory. I am using arrayofUniversities a list to populate a spinner so I need an adapter. I am populating the spinner with the names of the Universities
I am storing the University Objects in universitieslist
The problem I have is when I leave the readUniversity() method I lose every element in universitieslist and arrayofUniversities even though my spinner is populated with these.
Its very strange as the list should have the objects stored.
Also, I have my adapter at the very top of the code in onCreate().
Try this way. Hope it will work .. :)
private Arrylist<University > universityList = new ArryList<>();
private Arrylist<String> universitysName = new ArryList<>();
mDatabase.getReference().child("path")
.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if (dataSnapshot != null) {
University mUniversity = dataSnapshot.getValue(University
.class);
universityList.add(mUniversity);
universitysName.add(mUniversity.getName);
}
}
#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(DatabaseError databaseError) {
}
});
The problem seems to be with the adapter, if you can see the logs but the adapter is not updating, then is because the adapter is not being notified the data set has changed
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if (dataSnapshot != null) {
University mUniversity = dataSnapshot.getValue(University
.class);
universityList.add(mUniversity);
universitysName.add(mUniversity.getName);
//UPDATE YOUR ADAPTER HERE
//spinnerAdapter.notifyDataSetChanged();
}
}
But I think the real problem is the origin of your current problem: You are getting each child. This is a way to do it, but for this case where you need all the data first and when that is ready show the spinner with the elements to the user, you should better get all the list elements in one query.
database.getReference("note-retrieve/Universities")..addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
University mUniversity = dataSnapshot.getValue(University
.class);
universityList.add(mUniversity);
universitysName.add(mUniversity.getName);
//ONCE THIS IS DONE, THEN PASS THE ARRAY TO THE ADAPTER
}
//The loop here is over, so you can set the adapter with the full list of data/universities
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Related
how can I order my recyclerview items like this
mDatabaseReference = FirebaseDatabase.getInstance().getReference();
productQuery = mDatabaseReference.child("Blog").orderByChild("replaydate");
"replaydate" is located in Replay>psotkey>replaydate I want order blog items by repaydate, is this possiple?
If you want to get the messages by timestamp order you can use
database.orderByChild("replydate").limitToLast(10)
.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if (dataSnapshot.getValue() != null) {
Model newModel = dataSnapshot.getValue(Model.class);
//Model is you model which you are using for showing data in recyclerview
arraylist.add(newModel);
adapter.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(DatabaseError databaseError) {
}
});
This question already has an answer here:
ArrayList not updating inside onChildAdded function
(1 answer)
Closed 4 years ago.
I want to get the whole value(0~5) from destinations
This is part of json data in realtime database
{"results" : [{
"destin_num" : 6,
"destinations" : [ "asdf", "qwwee", "zzzxcv11", "jkkk", "lkjhhg", "zxcvb" ],
"name" : "asdfasdfff",
"order" : 2,
"required_time" : "6hours" }]}
the value I want to put in the String List , I use ChildEventListener() to add the value into List, but the value can't put into the List after finish the ChildEventListener().There will be nothing in List direction How to get the values?
List<String> direction=new ArrayList<String>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
DatabaseReference reference_contacts = FirebaseDatabase.getInstance().getReference("results").child("1").child("destinations");
reference_contacts.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String data=dataSnapshot.getValue().toString();
direction.add(data);
}
#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(DatabaseError databaseError) {
}
});
for(int i=0;i<direction.size();i++){
Log.e("Get data",direction.get(i));
}
}
It's because data is loaded from Firebase asynchronously. Your for loop printing the values is actually run before onChildAdded ever gets called. It's easiest to see this by adding some logging:
Log.i("Firebase", "Before adding listener");
reference_contacts.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Log.i("Firebase", "In onChildAdded");
}
#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(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
Log.i("Firebase", "After adding listener");
When you run this code it prints:
Before adding listener
After adding listener
In onChildAdded
That is probably not the order you expected. But is completely explains why the direction list is empty when you print it, the data hasn't been loaded yet, so onChildAdded has never been invoked.
The solution is typically to add the code that requires the data into the onChildAdded method:
So:
reference_contacts.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String data=dataSnapshot.getValue().toString();
direction.add(data);
Log.i("Got data",direction);
}
#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(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
If you only want to show the data once everything is loaded, you can use a ValueEventListener instead:
reference_contacts.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot: snapshot.getChildren()) {
String data=dataSnapshot.getValue(String.class);
direction.add(data);
}
for(int i=0;i<direction.size();i++){
Log.e("Get data",direction.get(i));
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
Note that this is an incredibly common source of confusion for developers new to Firebase (and asynchronous APIs in general). I highly recommend studying some of the answers to some of these previous questions about the topic:
Setting Singleton property value in Firebase Listener
getContactsFromFirebase() method return an empty list (which also shows how to define a custom interface to allow the code that requires the data to be outside onChildAdded/onDataChange.
can't get values out of ondatachange method
ArrayList not updating inside onChildAdded function
I am trying to delete an image and some data from firebase and remove these from my recyclerview.
I have successfully managed to accomplish this and it's deleting the image allright, but it's not instantly deleting the image in the interface.
I have to leave the activity and return in order to view the updated view.
this is my ChildEventListener:
mDBListener = mDatabaseRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
mUploads.clear();
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
Upload upload = postSnapshot.getValue(Upload.class);
upload.setKey(postSnapshot.getKey());
mUploads.add(upload);
}
mAdapter.notifyDataSetChanged();
mProgressCircle.setVisibility(View.INVISIBLE);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
mAdapter.notifyDataSetChanged();
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
what happens when i press delete:
#Override
public void onDeleteClick(int position) {
final Upload selectedITem = mUploads.get(position);
final String selectedKey = selectedITem.getKey();
Log.d(TAG, "SelectedKEY" + selectedKey);
StorageReference imageref = mStorage.getReferenceFromUrl(selectedITem.getImageUrl());
imageref.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if(user != null) {
Intent intent = getIntent();
Bundle bd = intent.getExtras();
String selectedId = (String) bd.get("selectedId");
mDatabaseRef.child(selectedId).child(selectedKey).removeValue();
Toast.makeText(ImagesActivity.this, "Item deleted ", Toast.LENGTH_SHORT).show();
}
}
});
}
and the onDestroy override:
#Override
protected void onDestroy() {
super.onDestroy();
mDatabaseRef.removeEventListener(mDBListener);
}
}
UPDATED TRY FOR SOLUTION
I tried for a solution and got a little bit closer to my goal.
Now when I delete an item in the view, and call for a Toast in my onChildRemoved, I get the toast. This is the code:
DatabaseReference mDatabaseRefff = FirebaseDatabase.getInstance().getReference(Uid).child(selectedId).child(selectedId).child(key);
dbEvent = mDatabaseRefff.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Toast.makeText(ImagesActivity.this, "Item deleted ", Toast.LENGTH_SHORT).show();
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
so basically I did not remove the old childeventlistener (Because it worked perfectly as it was supposed to work for everything else)
And now i put this childEventlistener below the first one, only now I am listening on the same child as I am trying to remove.
Now when I delete an item from the view, I get the Toast "Item deleted".
The problem is that when I add mAdapter.notifyDataSetChanged();
It still only shows the toast and nothing else happens...
I believe you need to Override onChildRemoved, remove the item from the adapter and call notifyDataSetChanged() to refresh the recyclerView.
onChildRemoved() Listen for items being removed from a list. The DataSnapshot passed to
the event callback contains the data for the removed child.
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
//add logic to remove item from adapter
String key = dataSnapshot.getKey();
//mAdapter.remove(index);
mAdapter.notifyDataSetChanged();
}
Following the update on the question, the next thing to do is simply update the Adapter, you detect what was removed from the database through the onChildRemove() and remove that from your adapter. Once you remove from the adapter, you simply call notifyDataSetChanged() and should work.
More info about Firebase Listen for child events
I didn't manage to find a solution in the childEventListener method. So I used valueEventListener instead and solved the issue.
The first 2 keys dont have child but others have them. I'm able to display the child elements when there is only one parent and I can display Admin/User details using data object model but how to display parent elements(Bright Kid Test & others) in Listview?
This is an image of Firebase Database:
Code:
listView = (ListView)findViewById(R.id.preschool_list);
adapter = new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,list);
listView.setAdapter(adapter);
databaseReference = FirebaseDatabase.getInstance().getReference("Preschools");
databaseReference.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String value = dataSnapshot.getValue(String.class);
list.add(value);
adapter.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(DatabaseError databaseError) {
}
});
If there is only one child of preschools then it is displayed else no value is shown.
I've got the answer with datasnapshot.getChildren().
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot dsp : dataSnapshot.getChildren())
{
list.add(String.valueOf(dsp.getKey()));
adapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
You want to display text Bright Kid LL, Bright Kid Mont, Bright Kid Test in list view, don't you? You can get them by getKey()
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot recipeSnapshot : dataSnapshot.getChildren()) {
String key = recipeSnapshot.getKey();
list.add(key);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
I have this query in my Firebase
mDataBase = FirebaseDatabase.getInstance().getReference("animals);
query = mDataBase.orderByChild("height").limitToLast(20);
query.addChildEventListener(new AnimalsEventListener());
My listener
private class AnimalsEventListener implements ChildEventListener{
private AnimalsEventListener(){
}
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Animals details = dataSnapshot.getValue(Animals.class);
}
#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(DatabaseError databaseError) {
}
}
How can I get the size of all animals that matched the query before working on dataSnapShot? sometimes they can be less than 20;
It's not possible to know children count using ChildEventListener, use ValueEventListener instead.
public class AnimalsEventListener implements ValueEventListener {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getChildrenCount() == 20) {
for (DataSnapshot dataSnapshotEntry : dataSnapshot.getChildren()) {
Animals details = dataSnapshotEntry.getValue(Animals.class);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
}
To attach this listener, use addValueEventListener() method
query.addValueEventListener(new AnimalsEventListener());
If you wanna use childEventListener i recommend u to use official FirebaseArray class.
To get the item count:
FirebaseArray mFirebaseArray = FirebaseArray(Query ref);
mFirebaseArray.getCount();