I'm trying to retrieve some string from firebase and trying to show them as the entries of an AppCompatSpinner.
Here's how I'm retrieving it:
vDatabase.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, String> newRequest = (Map<String, String>) dataSnapshot.getValue();
vName = newRequest.get("vName");
Toast.makeText(getBaseContext(), venueName, Toast.LENGTH_SHORT).show();
if (vName != null) {
ArrayList<String> spinnerArray = new ArrayList<>();
spinnerArray.add(vName);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
getBaseContext(), android.R.layout.simple_spinner_dropdown_item, spinnerArray);
venueSpinner.setAdapter(adapter);
} else {
Toast.makeText(getBaseContext(), "v == null", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
The problem is that above code is retrieving all the strings but showing only the last fetched string and not all of them.
What's wrong here and how can I show all the strings retrieved from the FirebaseDatabase?
Declare ArrayList spinnerArray = new ArrayList<>(); in your class not inside the onDatachange method
by keeping in onDatachange the variable is creating newly , so everytime new value is inserted in it ,so u are getting the last value to display.
Related
I am trying to store all children of my firebase database into an array list.
Here is my database structure:
I am currently trying to loop through children in order to get the values I need as follows:
private void initializeData(int Destination) {
listItems = new ArrayList<>();
DatabaseReference MyRef = FirebaseDatabase.getInstance().getReference("rideShare");
switch (Destination) {
case 0:
Toast.makeText(getActivity(), "LA BUNDLE", Toast.LENGTH_SHORT).show();
MyRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
for(DataSnapshot snapshot : dataSnapshot.getChildren()) {
String NameValue = snapshot.child("Name").getValue(String.class);
String Price = snapshot.child("Price").getValue(String.class);
String Type = snapshot.child("Trip Type").getValue(String.class);
String Date = snapshot.child("Date").getValue(String.class);
String Destination = "LA";
String Phone = snapshot.child("Phone Number").getValue(String.class);
listingItem newItem = new listingItem(NameValue, Type, Price, Date, Destination, Phone);
listItems.add(newItem);
}
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
//Log.w(TAG , "Failed to read value.",error.toException());
}
});
break;
}
}
Add all the string variables into a POJO class and name the variables same as the child nodes keys. Use snapshot.get(listingItem.class) directly instead.
Refer to this https://stackoverflow.com/a/39861649/3860386
To get those values, please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference rideShareRef = rootRef.child("rideShare");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<ListingItem> listItems = new ArrayList<>();
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String nameValue = ds.child("Name").getValue(String.class);
String type = ds.child("Trip Type").getValue(String.class);
String price = ds.child("Price").getValue(String.class);
String date = ds.child("Date").getValue(String.class);
String destination = "LA";
String phone = ds.child("Phone Number").getValue(String.class);
ListingItem newItem = new ListingItem(nameValue, type, price, date, destination, phone);
listItems.add(newItem);
}
Log.d("TAG", listItems);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
rideShareRef.addListenerForSingleValueEvent(eventListener);
When you are writting Java code, it's better to use Java Naming conventions. I added this code accordingly.
Also as you probaly see, i have added the declaration of listItems inside onDataChange() method, otherwise it will alwasy be null due the asynchronous behaviour of this method.
I have array list on android it's worked .
in past i was write the array string at the code like :
String[] string = {"st1","st2","st1"}
I was made connection the app to firebase and i was success to get string .
I want to get the string array from firebase, but i don't know how!
i was read about that but not helpful for me.
i was put the strings at the array list as function on Fragment.
so my code is :
private ArrayList<City> initCities() {
Log.d(TAG, "ArrayList_CitiesFragment_initCities");
String[] cityName = {"st1","st2","st3"};
ArrayList<City> theCities = new ArrayList<>();
for (String aCityName : cityName) {
City city = new City(aCityName, false);
theCities.add(city);
}
return theCities;
}
then at the onViewCreate operation the function.
i want it from the firebase.
i don't know how..
You need to add addValueEventListener() method to receive the events whenever there is change in data.
Here is the sample code as you have not mentioned clearly your database structure and what part you want to retrieve.
ArrayList<String> names = new ArrayList<String>;
final DatabaseReference ref = FirebaseDatbase.getInstance().getReferenece().child("Your_Child_Name");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot){
for(Map.Entry<String, Object> entry : ((Map<String, Object>) dataSnapshot.getValue()).entrySet())
{
Map singlet = (Map) entry.getValue();
names.add((String)singlet.get("COLUMN_NAME_OF_DATABASE_YOU_WANT"));
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(getApplicationContext(), "AWW SNAP... Something is Wrong.", Toast.LENGTH_LONG).show();
}
});
So this is how my database looks like. Each user can add his 3 best players that are stored in userId/My Players/ path as a Map<"Best Players", Player> as it is shown here:
List<String> list = new ArrayList<>();
list.add(first.getText().toString());
list.add(second.getText().toString());
list.add(third.getText().toString());
Players players = new Players(list);
Map<String, Object> map = new HashMap<>();
map.put("Best Players", players);
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
FirebaseDatabase database = FirebaseDatabase.getInstance();
if (user != null) {
DatabaseReference myRef = database.getReference().child("Users").child(user.getUid()).child("My Players");
myRef.setValue(map);
}
Player object contains ArrayList with 3 String objects. So, I would like to go through all users in database and search for each users 0th or 1st or 2nd player from his Best Players list. Any advice how to do that?
In order to display those lists, please use this code:
ListView listView = (ListView) findViewById(R.id.list_view);
ArrayList arrayList = new ArrayList<>();
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("Users").child(userId).child("My Players").child("Best Players").child("list");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
#SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) dataSnapshot.getValue();
String firstList = (String) map.get("0");
String secondList = (String) map.get("1");
String thirdList = (String) map.get("2");
arrayList.add(firstList + ", " + secondList + ", " + thirdList);
arrayAdapter = new ArrayAdapter<>(this, R.layout.list, arrayList);
listView.setAdapter(arrayAdapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
ref.addListenerForSingleValueEvent(eventListener);
you can use code given below: change parameters as per your database
databaseReference.child(Table_Dashboard).orderByChild("title").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
spin = new ArrayList<String>();
// spin.add("Dashboard");
for (DataSnapshot spinnerSnapshot : dataSnapshot.getChildren()) {
String areaName = spinnerSnapshot.child("title").getValue(String.class);
spin.add(areaName);
}
// spin.remove("Family Details");
ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(Dashboard.this, android.R.layout.simple_spinner_item,
spin);
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(spinnerAdapter);
dismissprogress();
}
#Override
public void onCancelled(DatabaseError databaseError) {
dismissprogress();
}
});
I am trying to write a firebase app that contains a simple ArrayList that will serve as feed for a list view.
In order to do so I have a singleton that takes care of FirebaseConnection and will fetch the data. This data is then feeded to the list. The problem is the data is first feeded to the list as null then the data is finished retrieving. Any solutions you might have for me?
Here is my code:
public ArrayList< Event > getAllEventsOnFirebase() {
final ArrayList< Event > events = new ArrayList<Event>();
DatabaseReference eventsTable = getDatabaseTableWith(Constants.tableEvents);
eventsTable.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
HashMap<String, Object> event = (HashMap<String, Object>) postSnapshot.getValue();
String eventId = (String) event.get(Constants.taEventUUID);
String eventName = (String) event.get(Constants.taEventName);
String eventAddress = (String) event.get(Constants.taEventAddress);
Event newEvent = new Event(eventId, eventName, eventAddress);
events.add(newEvent);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return events;
}
Also the way I populate the list is as follows:
eventsArray = FirebaseConnection.getInstance().getAllEventsOnFirebase();
EventListAdapter adapter = new EventListAdapter(this, eventsArray);
eventsListView.setAdapter(adapter);
Data is loaded asynchronously from Firebase. Luckily you can populate the ArrayList at any moment, as long as you tell the adapter that you changed it by calling adapter.notifyDataSetChanged().
public ArrayList< Event > getAllEventsOnFirebase(final EventListAdapter adapter,
final ArrayList<Event> events) {
DatabaseReference eventsTable = getDatabaseTableWith(Constants.tableEvents);
eventsTable.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
String eventId = postSnapshot.child(Constants.taEventUUID).getValue(String.class);
String eventName = event.child(Constants.taEventName).getValue(String.class);
String eventAddress = event.child(Constants.taEventAddress).getValue(String.class);
Event newEvent = new Event(eventId, eventName, eventAddress);
events.add(newEvent);
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
Now you can call it as:
ArrayList< Event > events = new ArrayList<Event>();
EventListAdapter adapter = new EventListAdapter(this, eventsArray);
eventsListView.setAdapter(adapter);
FirebaseConnection.getInstance().getAllEventsOnFirebase(adapter, events);
Currently, I'm building an Android App which is using a Firebase Database.
In my code, I'm trying to get the number of Children in a specific path of my Firebase Database. Having defined the reference of the Firebase specific path, I have made a Listener in order to get the DataSnapshot and then to call getChildrenCount().
After that, I want to use this result in a FOR-Loop. However, the code doesn't work.
It appears that it is executed first the FOR-Loop (I realised that because Log.v("NUM_OF_PRODUCTS",numOfProducts+"") outputs 0 insteed of 3) and the Listener is executed after, while in the code, listener code comes first and FOR-Loop code next.
Part of my code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_product_selection);
selected_cat = getIntent().getExtras().getString("pass_selected_cat");
listView = (ListView) findViewById(R.id.listView);
final ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, arrayList);
listView.setAdapter(adapter);
fbdatabase = FirebaseDatabase.getInstance();
fbref_products = fbdatabase.getReference("PRODUCTS/SM_0/" + selected_cat);
//Listener for getting numOfProducts.
fbref_products.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
numOfProducts = (int) dataSnapshot.getChildrenCount();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//Print numOfProducts before FOR-Loop being executed.
Log.v("NUM_OF_PRODUCTS",numOfProducts+"");
//FOR-Loop
for (int i = 0; i < numOfProducts; i++) {
String str = i + "";
DatabaseReference product_ref = fbref_products.child(str);
product_ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, Object> map = (Map<String, Object>) dataSnapshot.getValue();
String productName = (String) map.get("productName");
arrayList.add(productName);
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
//textView.setText("The read failed: " + databaseError.getMessage());
}
});
}
My code works fine if instead the variable numOfProducts, we had a specific number.
Could anyone help me??
Data from the Firebase Database is loaded asynchronously. By the time you run your for loop it hasn't been loaded yet.
It is easiest to see this if you place a few log statements in your code:
System.out.println("Before attaching listener");
fbref_products.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
System.out.println("In onDataChange");
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
System.out.println("After attaching listener");
When you run this, the output will be:
Before attaching listener
After attaching listener
In onDataChange
This is probably not the order that you expected. But it explains perfectly why numOfProducts is still 0 when you start the loop: the data simply hasn't been loaded from Firebase yet.
In initial reaction from pretty much every developer is "I don't want this. How do I make it execute in the right order?" This is a natural response, but one that you'll have to suppress to get anywhere when programming against web/cloud APIs. I also recommend reading my answer here: Setting Singleton property value in Firebase Listener
The solution is to reframe your solution from "first I'll get the number of products and then I'll loop over the products" to "whenever I get the products, I'll loop over them".
In code that is:
fbref_products.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
numOfProducts = (int) dataSnapshot.getChildrenCount();
for (int i = 0; i < numOfProducts; i++) {
String str = i + "";
DatabaseReference product_ref = fbref_products.child(str);
product_ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, Object> map = (Map<String, Object>) dataSnapshot.getValue();
String productName = (String) map.get("productName");
arrayList.add(productName);
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
//textView.setText("The read failed: " + databaseError.getMessage());
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Aside from the whole dealing with asynchronous events, you can significantly simplify this code:
fbref_products.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot productSnapshot: dataSnapshot.getChildren()) {
String productName = productSnapshot.child("productName").getValue(String.class);
arrayList.add(productName);
adapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Changes:
this uses only a single listener. Your second listener is not needed, since retrieving a node already retrieves all data under that node as well. You can loop over the child nodes.
this doesn't first extract a HashMap, but simply reads the data from the child snapshot directly.
One more change you should consider is to keep a separate list of product names. You now retrieve all product data to show a list of names, which is wasteful. If you keep a separate list of just the product names, you can load that instead. You'll find that a common theme when using Firebase (or almost any NoSQL database): model the data in your database the way you show it on the screen.