How to get the data under foods (product Name)?
I can get the data (with the check icon).
I want to get the data from the wrong icon.
Here is my MainActivity code for database reference
// getting Firebase Database reference to communicate with firebase database
private final DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference();
// creating List of MyItems to store user details
private final List<MyItems> myItemsList = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// getting RecyclerView from xml file
final RecyclerView recyclerView = findViewById(R.id.recyclerView);
// setting recyclerview size fixed for every item in the recyclerview
recyclerView.setHasFixedSize(true);
// setting layout manager to the recyclerview. Ex. LinearLayoutManager (vertical mode)
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
// clear old items / users from list to add new data/ users
myItemsList.clear();
// getting all children from users root
for (DataSnapshot Requests : snapshot.child("Requests").getChildren()) {
// to prevent app crash check if the user has all the details in Firebase Database
if (Requests.hasChild("askfor") && Requests.hasChild("tablet") && Requests.hasChild("total")) {
// getting users details from Firebase Database and store into the List one by one
final String getaskfor = Requests.child("askfor").getValue(String.class);
final String gettablet =Requests.child("tablet").getValue(String.class);
final String gettotal =Requests.child("total").getValue(String.class);
// final String getproductName =Requests.child("productName").getValue(String.class);
// creating user item with user details
MyItems myItems = new MyItems(getaskfor, gettablet, gettotal);
The foods node in your database looks like an array, so if you get its value in Java code you'll get a List.
So you can loop over the food children just as you do already for the requests children:
if (Requests.hasChild("foods") {
for (DataSnapshot foodSnapshot : Requests.child("foods").getChildren()) {
String productName = foodSnapshot.child("productName").getValue(String.class);
...
}
}
Unrelated: since your onDataChange implementation on seems to process the Requests node, it is more efficient to only load that node from the database, instead of loading the entire database.
So:
// 👇 Add here
databaseReference.child("Requests").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
// clear old items / users from list to add new data/ users
myItemsList.clear();
// getting all children from users root
// 👇 Remove here
for (DataSnapshot Requests : snapshot.getChildren()) {
...
Related
I am trying to retrieve data from Firebase Realtime Database and add this data to a listview. When I call push() firebase generates two children (one inside the other) with the same unique key. This is the structure of my database:
database
That is how I save the data:
RunningSession runningSession = new RunningSession(date, activityTime, pace, timeElapsed,
finalDistance, image, tipe);
DatabaseReference reference = databaseReference.child("users").child(userUid).child("activities").push();
Map<String, Object> map = new HashMap<>();
map.put(reference.getKey(),runningSession);
reference.updateChildren(map);
This is how i retrieve the data (results in a null pointer exception):
DatabaseReference reference = databaseReference.child("users").child(userId).child("activities");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
list.clear();
for (DataSnapshot snpshot : snapshot.getChildren()) {
RunningSession run = snpshot.getValue(RunningSession.class);
list.add(run);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
ListViewAdapter adapter = new ListViewAdapter(this, list);
ListView activityItems = (ListView) findViewById(R.id.activityList);
activityItems.setAdapter(adapter);
You are getting duplicate push IDs because you are adding them twice to your reference. If you only need one, then simply use the following lines of code:
RunningSession runningSession = new RunningSession(date, activityTime, pace, timeElapsed, finalDistance, image, tipe);
DatabaseReference reference = databaseReference.child("users").child(userUid).child("activities");
String pushedId = reference.push().getKey();
reference.child(pushedId).setValue(runningSession);
The code for reading that may remain unchanged.
I'm really new at android development, and trying to make app with firebase. I made signup with profile photo and pushed photo name into Database. And file to FireStore. At the bottom Code mImageUrls.add(uri.toString()); line doesn't work. But it makes toast in OnSuccess(), just I can't add data into array. I initialized Array in OnCreateView(final ArrayList<String> mImageUrls = new ArrayList<>();) like other arrays too. I need your help.
lv = (ListView) rootview.findViewById(R.id.lv_main);
final ArrayAdapter adapter = new MyAdapter(getActivity(), name_list,date,imgs);
myref = FirebaseDatabase.getInstance().getReference().child("MusiciansNonSensitive");
final ArrayList<String> mImageUrls = new ArrayList<>();
final StorageReference storageReference = FirebaseStorage.getInstance().getReference();
myref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot postSnapshot: snapshot.getChildren()) {
String name_value = postSnapshot.child("name").getValue().toString();
String province_value = postSnapshot.child("province").getValue().toString();
final String url_path = postSnapshot.child("photourl").getValue().toString();
StorageReference photo_url = storageReference.child("uploads/"+url_path);
photo_url.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
mImageUrls.add(uri.toString()); // I tried to add Log.d and it adds value every for loop, but after loop it being empty array again.
}
});
//mImageUrls.add("A");
name_list.add(name_value);
date.add(province_value);
}
Log.d("LOGGOGOGOOG",mImageUrls.toString()); // Here being empty
//Toast.makeText(getContext(),list.toString(),Toast.LENGTH_LONG).show();
lv.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
addOnSuccessListener is asynchronous and returns immediately. The callback is invoked some time later, even after the loop completes and your call to setAdapter. You're going to have to rewrite the code to only set the adapter after all the URLs have been fetched asynchronously. You can wait for a bunch of tasks to complete by using Tasks.whenAll() to get a new Task that will complete after the list of tasks you provide are fully complete.
I am not sure if I am understanding some of the literature correctly. Android documentation says don't create unecessary objects. This article (Are Firebase queries scalable) mentions scalability with DB queries is ok, but I've also read its better to store your Query into an ArrayList and search through that instead of querying a large DB.
In my case I am using Firebase Realtime Database for Android and I'm wondering if I get a Child Node that has maybe 200 examples/child nodes, should I put each of these snapshots into a Model Class and then Add each of those to an ArrayList which can then be displayed in a RecyclerView? Or Should I run .getValue() on the fields and store them in another way?
I am specifically looking to see which Company ID's an Employer is associated to, and then go to the Companies node and Get the Business Names and Business Cities for that Employer
DB:
Here is my section of code in the activity:
companiesRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot ds: dataSnapshot.getChildren()) {
Log.i("companiesSnap", ds.toString());
Log.i("KEYs", ds.getKey());
companyIDKey = ds.getKey();
//For each company ID in the Arraylist
for (int i = 0; i < myCompanyIDsList.size(); i++) {
//IF the IDs in arraylist from employee matches CompanyID from Companies node
if(myCompanyIDsList.get(i).equals(companyIDKey)) {
//IF THE ID matches, then get the associated company info
Log.i("city", ds.child("businessCity").getValue().toString());
Log.i("name", ds.child("businessName").getValue().toString());
Businesses business = new Businesses(ds);
myBusinessListItems.add(business);
mAdapter.updateDataSet(myBusinessListItems);
}
}
Entire Class:
public class BusinessesActivity extends Activity {
private Context mContext;
LinearLayout mLinearLayout;
private RecyclerView mRecyclerView;
private MyAdapterBusiness mAdapter = new MyAdapterBusiness(this);
private RecyclerView.LayoutManager mLayoutManager;
ArrayList<Businesses> myBusinessListItems;
ArrayList<String> myCompanyIDsList;
DatabaseReference employeesRefID, companiesRef;
FirebaseDatabase database;
String currentUser, companyIDKey;
TextView getData;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_businesses);
//RECYCLERVIEW STUFF
mRecyclerView = (RecyclerView) findViewById(R.id.b_recycler_view);
mContext = getApplicationContext(); // Get the application context
// Define a layout for RecyclerView
mLayoutManager = new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false); //mLayoutManager = new LinearLayoutManager(mContext);
mRecyclerView.setLayoutManager(mLayoutManager);
// Initialize a new instance of RecyclerView Adapter instance
mRecyclerView.setAdapter(mAdapter);
//ARRAY List to Store EACH Company ID
myCompanyIDsList = new ArrayList<String>();
myBusinessListItems = new ArrayList<Businesses>();
currentUser =
FirebaseAuth.getInstance().getCurrentUser().getUid();
database = FirebaseDatabase.getInstance();
getData = (TextView) findViewById(R.id.getData);
companiesRef = database.getReference("Companies").child("CompanyIDs");
final DataSnapshotCallback callback = new DataSnapshotCallback() {
#Override
public void gotDataSnapshot(DataSnapshot snapshot) {
EmployeeUser employee = new EmployeeUser(snapshot);
//myCompanyIDsList.add(employee);
try {
for (DataSnapshot ds : snapshot.getChildren()) {
//WITHIN each UserId check the PushID
Log.i("TAG", "checkIfIDExists: datasnapshot: " + ds);
myCompanyIDsList.add(ds.getValue(EmployeeUser.class).getID());
Log.i("arrayList", myCompanyIDsList.toString());
//}
}
//GO THROUGH EACH COMPANY ID AND FIND INFORMATION
companiesRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot ds: dataSnapshot.getChildren()) {
Log.i("companiesSnap", ds.toString());
Log.i("KEYs", ds.getKey());
companyIDKey = ds.getKey();
//For each company ID in the Arraylist
for (int i = 0; i < myCompanyIDsList.size(); i++) {
//IF the IDs in arraylist from employee matches CompanyID from Companies node
if(myCompanyIDsList.get(i).equals(companyIDKey)) {
//IF THE ID matches, then get the associated company info
Log.i("city", ds.child("businessCity").getValue().toString());
Log.i("name", ds.child("businessName").getValue().toString());
Businesses business = new Businesses(ds);
myBusinessListItems.add(business);
mAdapter.updateDataSet(myBusinessListItems);
}
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d("Cancelled", databaseError.toString());
}
}); //END COMPANIES EVENT LISTENER
//} //END FOR
} //END TRY
catch (Exception e) {
Log.i("FNull?", e.toString());
}
//mAdapter.updateDataSet(myListItems);
}
};
getData.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View view) {
employeesRefID = database.getReference("Employees").child(currentUser).child("Companies"); //SEE HOW ADD EMPLOYEES checks
employeesRefID.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
callback.gotDataSnapshot(dataSnapshot);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d("Cancelled", databaseError.toString());
}
}); //END EMPLOYEE EVENT LISTENER
Log.i("OutsideEvent", myCompanyIDsList.toString());
}
}); //END ONCLICK
Log.i("OutsideonClick", myCompanyIDsList.toString());
}
interface DataSnapshotCallback {
void gotDataSnapshot(DataSnapshot snapshot);
}
}
The trick to reducing memory usage when using Firebase is to only load data that you're going to display to the user.
If you need a list of just business names, create a nodes with just the business names in the database and display that. That way you've reduce both the bandwidth and the memory used, since you're not loading the other properties of the company.
You'll typically have one "master list" with all properties of each company (or other entity type). And then you may have one or more "display lists" that contain only the information of the business that you need to display in certain areas. This duplicated data is quite common in NoSQL databases, and is known as denormalization.
For a better introduction, read Denormalizing Your Data is Normal, NoSQL data modeling, and watch Firebase for SQL developers.
My app has two categories of users shop owner and buyers.
When shop owner adds a shop I use his UID and then pushkey to add a shop like this:
In the Image "83yV" and "FmNu" are the shop owners and they add 2 and 1 shop respectively.
Now for buyers, I want to show the whole list of shops in a Recycler View.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_shops_avtivity);
shopsDB = FirebaseDatabase.getInstance().getReference().child("shops");
}
#Override
protected void onStart() {
super.onStart();
FirebaseRecyclerAdapter<Shop,ShopViewHolder> firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Shop, ShopViewHolder>(
Shop.class,
R.layout.shop_single_layout,
ShopViewHolder.class,
shopsDB)
}
The problem is when I point my Firebase Recycler Adapter to shopDB, it returns two empty cardView like this:
When I point it to specific child like
shopsDB = FirebaseDatabase.getInstance().getReference().child("shops").child("83yV24a3AmP15XubhPGApvlU7GE2");
It returns shops add by "83yV".
How can I get the shops added by other owners also? Preferably without altering current DB or creating one DB with all shops in it within on child.
To achieve this, you need to use getChildren() method twice, once to get all the users and second to get all the shops.
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference shopsRef = rootRef.child("shops");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
for(DataSnapshot dSnapshot : ds.getChildren()) {
String name = dSnapshot.child("name").getValue(String.class);
Log.d("TAG", name);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
shopsRef.addListenerForSingleValueEvent(eventListener);
Using this code, you'll be able to display all shop names to the buyers.
Can someone please advice me on this issue:
I am trying to load some filtered data from Firebase DB onCreate and populate a custom array with data.
After doing some debugging I can tell that the data is loaded from DB but my custom array is not getting populated.
Please have a look at my code below.
Even though my loadAllBooks() method is populating the array, it gets completed too late and the line:
//3) Create the adapter
BooksAdapter adapter = new BooksAdapter (this, booksList);
is executed before loadAllBooks() is completed which results in an empty list...
It's as if i need some sort of onComple for the addChildEventListener...
Please Help, if more information is needed let me know, thank you:
ArrayList<BookItem> booksList;
ListView listView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//1) empty books list
booksList = new ArrayList<BookItem>();
//2) load all books from firebase DB - into booksList array
loadAllBooks();
//3) Create the adapter
BooksAdapter adapter = new BooksAdapter (this, booksList);
//4) Attach the adapter to a ListView
listView = (ListView) findViewById(R.id.lvBooks);
listView.setAdapter(adapter);
}
public void loadAllBooks() {
Firebase ref = new Firebase(".......firebaseio.com/books");
Query queryRef = ref.orderByChild("bookType").equalTo("drama");
queryRef.addChildEventListener(childEventListener);
}
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded (DataSnapshot bookNode, String previousChild){
BookItem bookItemModel = bookNode.getValue(BookItem.class);
booksList.add(bookItemModel);
}
public void onChildRemoved(DataSnapshot snapshot) {}
public void onChildChanged(DataSnapshot snapshot, String previousChild){}
public void onChildMoved(DataSnapshot snapshot, String previousChild) {}
#Override
public void onCancelled(FirebaseError firebaseError) {}
};
Thank you!
When you call addChildEventListener() Firebase starts loading the data from the remote location asynchronously. This means that the code after it executes straight away and you pass an empty list to the adapter. Later, when the initial data has synchronized from Firebase, it is added to the list. But by that time you've already created the adapter.
You can most easily see the flow, by adding a few log statements:
System.out.println("Start loading/synchronizing books");
loadAllBooks();
System.out.println("Creating adapter");
BooksAdapter adapter = new BooksAdapter (this, booksList);
public void onChildAdded (DataSnapshot bookNode, String previousChild){
System.out.println("Adding book to list");
BookItem bookItemModel = bookNode.getValue(BookItem.class);
booksList.add(bookItemModel);
}
These will print in this order:
Start loading/synchronizing books
Creating adapter
Adding book to list
Adding book to list
Adding book to list
...
Likely this is not the order that you expected. Welcome to asynchronous loading 101, it makes the modern web tic and makes developers lose their mind when they first encounter it. :-)
Most likely all that is required is that you call adapter.notifyDataSetChanged() from onChildAdded(). This informs Android that the data in the adapter has changed and that it should repaint the associated view(s).
public void onChildAdded (DataSnapshot bookNode, String previousChild){
BookItem bookItemModel = bookNode.getValue(BookItem.class);
booksList.add(bookItemModel);
adapter.notifyDataSetChanged();
}
Note that I can't be sure if this will work, because you didn't include the code for BooksAdapter in your question.