I am using the Material SearchView which is provided by the library 'com.miguelcatalan:materialsearchview:1.4.0'. This library uses setSuggestions to set suggestions into the search view like i shown in the following code. But the setSuggestions allows String[] only. I want to load a list of items from the firebase and put in to the suggestion. The problem is that setSuggestion does not allow ArrayList.
materialSearchView.setOnSearchViewListener(new MaterialSearchView.SearchViewListener() {
#Override
public void onSearchViewShown() {
//Do some magic
mProgress.setMessage("Loading...");
mProgress.show();
mDatabasePlaces.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot data:dataSnapshot.getChildren()){
Place models=data.getValue(Place.class);
placelist.add(models.getName());
}
mProgress.dismiss();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
materialSearchView.setSuggestions(placelist);
}
#Override
public void onSearchViewClosed() {
//Do some magic
}
});
}
In the code placelist is an ArrayList which is not allowed in the materialSearchView.setSuggestions(placelist); So how can I put that list of places into setSuggestions.
You can parse it to String[] like this
String[] parsedArray = placelist.toArray(new String[placelist.size()])
Due the asynchronous behavior of onDataChange method, to get your work done, please move the following line of code:
materialSearchView.setSuggestions(placelist);
Inside onDataChange method right after this line of code:
mProgress.dismiss();
As also Artur Akhnoyan mentioned in his answer, please change the argument from placelist to:
placelist.toArray(new String[placelist.size()])
Related
In my RegistrationActivity.java class file I've declared a numOfUsers variable to count the number of users in my database.
import ...
public class RegistrationActivity extends AppCompatActivity {
//Other declarations
private static long numOfUsers;
I've created an event listener for checking if a particular user exists in the database. Inside this event listener there is another event listener which counts the total number of users in the database.
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(!dataSnapshot.exists()) {
//create new user
database.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
numOfUsers = dataSnapshot.getChildrenCount();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
//Displaying the numOfUsers in app
userinfo.setText(String.valueOf(numOfUsers));
}
This prints 0. If I place userinfo.setText(String.valueOf(numOfUsers)); inside the second event listener then everything works fine.
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(!dataSnapshot.exists()) {
//create new user
database.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
numOfUsers = dataSnapshot.getChildrenCount();
//This works perfectly fine
userinfo.setText(String.valueOf(numOfUsers));
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
I don't understand why this is happening. numOfUsers is a static class variable I should be able to access it's value from anywhere inside the class. Is there a way I can't print numOfUsers outside the second event listener?
It's not about where you access the data, but about when you access it.
Data is loaded from Firebase (and most modern cloud APIs) asynchronously, since it may take some time to get back.
Instead of blocking your main thread (which would lock out the user), your main code actually continues to run while the data is being loaded. Then when the data is available, your onDataChange gets called with it.
This means that in your code the userinfo.setText(String.valueOf(numOfUsers)) outside of onDataChange runs before onDataChange ever executes and thus passes the wrong value to the text view.
The solution for this is always the same: any code that needs the data from the database must be inside the onDataChange, or be called from there.
This is an incredibly common source of confusion, so I recommend reading more on:
getContactsFromFirebase() method return an empty list
Setting Singleton property value in Firebase Listener
Get the whole values from one key in firebase
Retrieve String out of addValueEventListener Firebase
I have a util class which helps me to get specific data from Firebase database the class like that
public class FirebaseUtils {
private DatabaseReference root;
public FirebaseUtils(){
root = FirebaseDatabase.getInstance().getReference();
}
public void setUerType(Context context,String userid){
DatabaseReference reference = root.child("teachers").child(userid);
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
PrefsHelper.getInstance(context).setUserType("teacher");
}else {
PrefsHelper.getInstance(context).setUserType("student");
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
what is the best way to remove the listener should I creat a method in utile class like that
public void removeListener(){
child.removeEventListener(listener);
}
and call it in onDetach method in the activity?
Yes, but in your case need to create a member of listener's type and not pass anonymous listener's implementation.
As I see in your code, you are using addListenerForSingleValueEvent(), which means that the listener will read the data precisely once. That means that your onDataChange() method gets triggered with the current value (from the cache if available, otherwise from Firebase servers), and stop listening immediately after that. In this case there is no need to remove the listener.
The only time addListenerForSingleValueEvent needs to be canceled is, if there is no network connection when you attach it and the client doesn't have a local copy of the data, either because there was another active listener or because it has a copy of the data on disk.
So in conclusion, there is no need to create a removeListener() method at all.
I have a app in building proccess in some where i need to get data from FirebaseDatabase and show them in custom list view here my code part of it for onDataChange method
myDatabase=FirebaseDatabase.getInstance();
myRef= myDatabase.getReference().child("TvSeries");
myAuth = FirebaseAuth.getInstance();
myUser = myAuth.getCurrentUser();
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot currentData : dataSnapshot.getChildren()){
if(currentData.child("tCategory").child("tPrimary").getValue().toString().equals("Aksiyon")){ }
selectedCategoryList.add(new DataForRow(currentData.getKey(),
currentData.child("tCategory").child("tPrimary").getValue().toString(),
currentData.child("tReleaseDate").getValue().toString()));
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Integer size =selectedCategoryList.size();
Log.d("Size:", size.toString());
When i put in breakpoint onDataChange method it works but otherwise it didnt any suggestion is very helpful. Have a nice day all.
Your selectedCategoryList list is always empty because onDataChange() method has an asynchronous behaviour which means that is called even before you are try to add those objects of DataForRow class to the list. A quick solve for this problem would be to declare and use your selectedCategoryList list only inside the onDataChange() method or if you want to use it outside, you need to create your own callback and for that, I recommend you see the last part of my answer from this post.
Firebase works asynchronously. You probably got the data from firebase after you program executed the line with Log. As Tristan mentioned, if you put your Log inside of the listener, it will work
so the Code looks like this right now.
The Problem is that I get more than one Logprints. But I need only the full and finished meberList.
for (String memberByNumber : memberListByNumber) {
mFirebaseDatabaseReference.child("userUidsByNumber/").child(memberByNumber).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
String userUid = dataSnapshot.getValue().toString();
memberList.add(userUid);
Log.d("LOL", "ContactsAdapter: " + memberList);
} else {
Snackbar.make(view, R.string.user_does_not_exist, Snackbar.LENGTH_LONG).show();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Snackbar.make(view, R.string.error, Snackbar.LENGTH_LONG).show();
}
});
}
I hope you understand my Problem and can help me.
Thanks in advance.
If onDataChange gets called for every member for memberListByNumber, then you can try
final int total = memberListByNumber.size();
for (String memberByNumber : memberListByNumber) {
mFirebaseDatabaseReference
.child("userUidsByNumber/")
.child(memberByNumber)
.addValueEventListener(new ValueEventListener() {
int n = total;
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
String userUid = dataSnapshot.getValue().toString();
memberList.add(userUid);
if (--n <= 0) Log.d("LOL", "ContactsAdapter: " + memberList);
} else {
Snackbar.make(view, R.string.user_does_not_exist, Snackbar.LENGTH_LONG).show();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Snackbar.make(view, R.string.error, Snackbar.LENGTH_LONG).show();
}
});
}
I want to comment it but due to my reputation here I couldn't
So, here is my answer your logging every entry into one file so that it just makes printing the necessary entries much harder So go on different path and give one more if-else statement in existing one and use try-exception to divide the finished and canceled into some cache memory and then void the finished file
In firebase, there's never a thing as complete list.
Value events keep happening whenever any data changes under any of the child nodes. Also value events happen last ie after all child events are finished ensuring all children nodes at that point are present. Next event will give you the complete list at that particular point.
On each data change call, you can clear the list, add all the new values and print that. This is how firebase works.
If you want the entire list only once and don't want any new changes, you can add the value event listeners using addListenerForSingleValueEvent method. Now the list will be read once and no more. However if you have persistence enabled, the data will be read once from the phone cache and not from the db
Maybe what you are looking for is a ChildEventListener which will give you more granular control. This will have child added, deleted and changed events which will give you the list data one child at a time.
I don't know what your actual purpose is so this is the best i can try to explain. Hope this helps
I'm trying to access a certain value within the last added Firebase node. In my database I have a set of Clients, which through my app, can be added to. Inside a client there's a piece of information titled 'clientName'. I would like to get this value.
Once I get the value, I'm trying to give a toast message showing that value.
Here is my code inside the onClick method of my button. I'm not sure why it's not working. If you know of another way I could do this or a way to fix my current code I'd really appreciate it!
Thanks in advance guys!
my_button[bt].setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (my_button[Index].getId() == ((ImageButton) v).getId()) {
String bla = (String) getIntent().getExtras().get("id");
String address = "https://console.firebase.google.com/project/cssecond-92a2d/database/data/clients/" +bla+"/clientName";
Firebase ref = new Firebase(address);
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(com.firebase.client.DataSnapshot dataSnapshot) {
String value = (String) dataSnapshot.getValue();
Toast.makeText(HomePageNews.this,"In your hands you have: "+ value ,Toast.LENGTH_LONG).show();
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
}
});
Everything looks fine in your code. The problem is this line of code:
String bla = (String) getIntent().getExtras().get("id");
The id that is returning from that intent is null, so your reference is also null. In order to fix this, you need to change the code to get the correct value from the intent that is coming from your previous activity and than it should work.