I have a firebase backend for my android app. I've pulled the data I need from the backend (Names of different players) and put it in an arraylist of Strings ..For example
{"John Doe1", "John Doe2"...."John Doe15"}
I now need to populate 15 different textviews Ids with these names for my activity. What is the most efficient way to do this? Here is my code so far and here is what my activity looks like...
public void onDataChange(DataSnapshot dataSnapshot) {
ArrayList<String> al= new ArrayList<String>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Player player = snapshot.getValue(Player.class);
String name=player.Name;
al.add(name);
}
You should place all the TextView and their desired ids into HashMap, like this:
// init object
HashMap<Integer, TexView> textViewMap = new HashMap<>();
... onCreate(...) {
....
// put value inside
TextView textView1 = (TextView) findViewById(R.id.text_view_1);
textViewMap.put(1, textView1);
...
}
Then when you get data from Firebase Database, you can use stored id you placed there to indicate which TextView the data belongs:
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
// if you use custom Player object, replace following line
Integer id = snapshot.child("id").getValue(Integer.class);
String name = snapshot.child("name").getValue(String.class);
// then get the TextView and put text in it
textViewMap.get(id).setText(name);
}
...
}
That should do it. Hope this helps.
Related
My Firebase Realtime Database is like this :
{Singer :
Billie Eilish :
01 :
songType : "type01"
songName : "bad guy"
02 :
songType : "type02"
songName : "bury a friend"
Lauv :
01 :
songType : "type01"
songName : "I Like Me Better"
02 :
songType : "type03"
songName : "lonely"
Anne Marie :
01 :
songType : "type02"
songName : "2002"
...
...
...
}
If I want to get all the song that "type01", what should I do? This is my Adapter class that show the data in recyclerView in MainActivity.
Adapter class :
public class MyAdapter extends Recycler.Adapter {
...
#Override
public void onBindViewHolder(#Nonnull ViewHolder holder, int i) {
...
Query query = FirebaseDatabase.getInstance().getReference().child("Singer");
options = new FirebaseRecyclerOptions.Builder<ItemModel>().setQuery(query, new SnapshotParser<ItemModel>() {
#NonNull
#Override
public ItemModel parseSnapshot(#NonNull DataSnapshot snapshot) {
if (snapshot.child("songType").getValue().toString().equals("type01") {
String song = snapshot.child("songName").getValue().toString();
return new ItemModel(song);
}
return null;
}
}).build();
recyclerAdapter = new AnotherAdapter(options);
recyclerAdapter.startListening();
}
I think it is weird in the query. It called only the child "Singer". I want to call all the child and get what songType is "type01". AnotherAdapter is just extending FirebaseReyclcerAdapter and just set the text in its AnotherViewHolder.
why don't you just go with fetch data which contains only songType : type01 try this
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = reference.child("Singer").orderByChild("songType").equalTo("type01");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot issue : dataSnapshot.getChildren()) {
//set featched value to recyclerview
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Since you're passing a reference to Singers into the recycler view, your parseSnapshot is called for each singer. In there you need to make sure you check the songType of each song child of the singer, where now you check the songType of the singers themselves (which never exists, so never goes into the if block).
So it'd be something like this:
Query query = FirebaseDatabase.getInstance().getReference().child("Singer");
options = new FirebaseRecyclerOptions.Builder<ItemModel>().setQuery(query, new SnapshotParser<ItemModel>() {
#NonNull
#Override
public ItemModel parseSnapshot(#NonNull DataSnapshot snapshot) {
String song = "No song found";
for (DataSnapshot songSnapshot: snapshot.getChildren()) {
String songType = songSnapshot.child("songType").getValue(String.class)
if (songType.equals("type01") {
song = songType;
...
I'm not sure though if this is what you want, because you seem to want a list of songs, while you're passing in a list of singers. The above will only work if each singer has exactly one song of type01 (not 0, not more).
If that is not the case, the adapters in FirebaseUI won't fit your needs with your current data structure, since they show a list of items from the database, while you want to show items from a tree-like structure.
The two main options that come to mind in that case:
Build your own adapter, typically based on ArrayAdapter as shown here.
Change your data structure so that all songs are in a flat list (and the singer then becomes a property of each song).
Here is my problem, I want to show all phone numbers in RecyclerView, how?
databaseReference = firebaseDatabase.getReference("CallLog");
//in on data change method using for
CallLogList logList = snapshot.getValue(CallLogList.class);
list.add(logList);
ArrayList<HashMap<String, String>> arrayList = new ArrayList<HashMap<String,String>>();
HashMap<String, String> map = new HashMap<String, String>(); map.put("phone",phoneNumber);
map.put("name",callName);
map.put("callType",dir);
map.put("date",dateString);
map.put("duration",callDuration+" seconds");
arrayList.add(map);
myRef.push().setValue(arrayList);
After getting the whole list from Firebase iterate them one by one to add them in the list, after the loop set them in the adapter of RecyclerView, and set the adapter to your desired RecyclerView
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
list = new ArrayList<CallLogList>();
for(DataSnapshot dataSnapshot1 :dataSnapshot.getChildren()){
CallLogList logList = snapshot.getValue(CallLogList.class);
list.add(logList);
}
yourAdapter = YourAdapter(list);
yourRecyclerView.setAdapter(yourAdapter);
}
For more info, here is a full example
Note: If you are using LiveData or Paging then setting adapters is different, Let me know if you need more example
First you should change the tree to be like this:
Call Log
-Calls
--Lhe...
---CallType OUTGOING
--Lhe...
---CallType INCOMING
Next, create "Calls" class in your project with the same fields as in the firebase, so callType, date, duration and phone.
After that, with this code, you can get all instances from the database into a list:
public void refreshList(DataSnapshot dataSnapshot) {
List<Class> list = new ArrayList<>();
for (DataSnapshot dataSnapshot1 : dataSnapshot.child("Calls").getChildren())
{
Item value = dataSnapshot1.getValue(Calls.class);
list.add(value);
}
}
Now you have a list of objects of class Calls, from which you can easily access the phone numbers.
I have this in the database:
When a teacher adds a Class and a Section a random id is generated using push() under node Class.
There is also a Student and a Teacher node with ids and attributes.
The student joins a class, thus also creating a random id in ClassStudent with the above attribute.
In node Student the id is the current userid and under it there is attribute. Now my question is, is it a good way to retrieve the name from the Student node and add it to the ClassStudent node?
Im using this code:
DatabaseReference gets=FirebaseDatabase.getInstance().getReference().child("Student");
final DatabaseReference getid=FirebaseDatabase.getInstance().getReference().child("Class");
ValueEventListener valueEventListener1= new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot child: dataSnapshot.getChildren()) {
String classnames = child.child("Classname").getValue().toString();
if (returnString.equals(classnames)) {
String getids = child.getKey();
newtable.child("ClassId").setValue(getids);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
getid.addValueEventListener(valueEventListener1);
The reason I have a name because later on I want to click on a class and get the list of names in that class. So if i add the Student id(which is done already) in node ClassStudent, how will I be able to on click retrieve the name of the Students without having studentname in ClassStudent?
Edit:
If I query on ClassStudent , I want to retrieve the class names in one activity then on another activity, I want to retrieve the Students names of a class. I dont want Studentname to be inside ClassStudent since logically I think it seems incorrect.
Example:
1. Student registers himself in a class (a random id with attribute classid and studentid is created).
Then I want to retrieve the classnames in onResume(), so after login the classes are there in activity(like a join between ClassStudent and Class`)
On completely different activity, I want to retrieve the studentnames in a list while also querying on ClassStudent (like a join between ClassStudent and Student)
Output of # 3. after querying:
Peter Haddad
John
Phillip
//names
To get all the stundet names under the ClassStudent node, please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference classStudentRef = rootRef.child("ClassStudent");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String Studentname = ds.child("Studentname").getValue(String.class);
Log.d("TAG", Studentname);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
classStudentRef.addListenerForSingleValueEvent(eventListener);
Your out out will be:
Peter Haddad
//other names
my data look like this
and I simply want to add an object at index 3. How could I add it there. Is there any way to add an object without iteration or I have to iterate and getChildCount and then append new child("3") and it's data to it.
TransGenderBO transGenderBO = new TransGenderBO();
transGenderBO.setName("pushName");
transGenderBO.setAge(13);
mRef.child("").setValue(transGenderBO);
there is no method in mRef for getting child count and appending new item at 3 position..
Edit after using Frank code but still not working
Query last = mRef.orderByKey().limitToLast(1);
last.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int lastIndex = 0;
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
lastIndex = Integer.parseInt(childSnapshot.getKey());
}
TransGenderBO transGenderBO = new TransGenderBO();
transGenderBO.setName("pushName");
transGenderBO.setAge(13);
mRef.child(""+(lastIndex+1)).setValue(transGenderBO);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(mContext,databaseError.getMessage(),Toast.LENGTH_LONG).show();
}
});
There is a good reason that the Firebase documentation and blog recommend against using arrays in the database: they don't work very well for multi-user applications where users can be offline.
To add the next element to your array here, you'll have to download at the very least the last element of the array to know the index of the next element:
Query last = root.orderByKey().limitToLast(1);
last.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int lastIndex;
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
lastIndex = Integer.parseInt(childSnapshot.getKey());
}
root.child(""+(lastIndex+1)).setValue(true);
}
But this has an inherent race-condition. When multiple users are adding elements to the array at the same time, they may end up writing to the same index.
To prevent this you can use a Firebase transaction. With this you get the current value from a location and in exchange return the new value you want at that location. This ensures that no data is overwritten between users, but means that you have to download the entire array.
And neither of these scenarios works when a user is not connected to the network.
Firebase instead recommends using so-called push IDs, which:
Generate a always-increasing key that is guaranteed to be unique.
Do not require reading any data - they are generated client-side and are statistically guaranteed to be unique.
Also work when a user is offline.
The only disadvantage is that they're not as easily readable as array indexes.
Get your data like this
private ArrayList<TransGenderBO> transGenderBO;
FirebaseDatabase.getInstance().getReference().child("Main")
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
transGenderBO = (ArrayList<TransGenderBO>) dataSnapshot.getValue();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
and set your value like this
TransGenderBO transGender = new TransGenderBO();
transGender.setName("pushName");
transGender.setAge(13);
FirebaseDatabase.getInstance().getReference().child("Main").child(String.valueOf(transGenderBO.size())).setValue(transGender);
or U can set this way too
TransGenderBO transGender = new TransGenderBO();
transGender.setName("pushName");
transGender.setAge(13);
TransGenderBO.add(transGender);
FirebaseDatabase.getInstance().getReference().child("Main")
.setValue(transGenderBO);
I am trying to query Firebase and populate a recycler adapter with conditional data from the query's DataSnapshot. I tried putting the populate function inside the if statement that correctly logs the data I want, however the recycler view instead just returns everything from the node I was searching in (the main query I started with). Any suggestions on how to just populate the items that apply to the "if" statement? Thank you!
rootRef = FirebaseDatabase.getInstance().getReference();
//below is the node i query
mAlbumQuery = rootRef.child(Constants.FIREBASE_CHILD_ALBUMS).orderByChild("genres");
mAlbumQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot reco : dataSnapshot.getChildren()) {
if (reco.getValue().toString().contains(mRecommendation.getGenre())) {
//below returns the items i want
Log.d("is this correct", reco.getValue().toString());
//below returns everything in the original query
//how to populate only items that match the above?
mAdapter = new FirebaseRecyclerAdapter<Album, AlbumsViewHolder>(
Album.class,
R.layout.album_cards,
AlbumsViewHolder.class,
mAlbumQuery) {
#Override
public void populateViewHolder(AlbumsViewHolder holder, Album album, int position) {
holder.bindView(album.getImage(), album.getTitle());
if (!album.getGenres().contains(mRecommendation.getGenre())) {
//added as a hypothetical... should i have something in here?
}
}
};
mAlbumsRecycler.setAdapter(mAdapter);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return view;
}
if you want to extract any particular node u can use this:-
String notific = String.valueOf(dataSnapshot.getValue());
int key=dataSnapshot.getKey();
String title=String.valueOf(dataSnapshot.child("title").getValue());
String content=String.valueOf(dataSnapshot.child("content").getValue());
Well, if you send mAlbumQuery as param to your FirebaseRecyclerAdapter, I believe, it takes its size as number of items.
As an option (for quick fix) you can create new collection and inside this loop:
for (DataSnapshot reco : dataSnapshot.getChildren()) {
}
you can fill that new collection with needed items.
After loop you can create new adapter and pass filtered collection to it.
Here is how I see this:
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Collection<> myNewCollection = new Collection<>(); //HashMap, ArrayList - depends on what you are storing in Firebase
for (DataSnapshot reco : dataSnapshot.getChildren()) {
if (reco.getValue().toString().contains(mRecommendation.getGenre())) {
//below returns the items i want
Log.d("is this correct", reco.getValue().toString());
//below returns everything in the original query
//how to populate only items that match the above?
myNewCollection.add(reco.getValue);
}
}
recyclerView.setAdapter(new MyRecyclerViewAdapter(myNewCollection, ...));
}
Also pls take a look at Firebase docs and this SO question.
There are interesting methods - startAt, endAt and equalTo, which might help you. I didn't find method contains, unfortunately, but methods above might be enough for you.