I am trying to write unit tests for methods that load and add data from Firebase DB. I have not found any resources to help me with this. can someone point me to a resource or post a sample code? for example, this is my load method
public ArrayList getGroceryData(final String type) {
tempBuilder=new ArrayList<>();
test=false;
databaseReference.child("Tasks").child(type).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot d : dataSnapshot.getChildren()) {
tempBuilder.add(d.getValue(Task.class));
}
test=true;
// Dashboard.populatefeed(tempBuilder);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
while(!test);
test=false;
return tempBuilder;
}
Related
I am creating an android app using firebase. My firebase database structure is as follow-
Users:{
uid:{
name:Bruno,
age: 22,
email: bruno#gmail.com,
address:...
}
},
Level_info:{
uid:{
score:70,
level:5
}
}
Before Rxjava, I retrieve all users like this-
userRef.addValueEventListener(new ValueEventListerner(){
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(Datasnapshot snapshot:dataSnapshot.getChildren())
{
User user = snapshot.getValue(User.class);
userList.add(user);
//to get score and levels
/*I can't add nested value event listener directly because of Asynchronous behavior */
userId.add(user.getId());
}
getLevels(userId);
}
#Override
public void onCancelled(DatabaseError error) {
//handle errors
}
});
void getLevels(final ArrayList<String> userid){
levelRef.addValueEventListener(new ValueEventListener(){
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(String id:userid)
{
Level level = dataSnapshot.child(id).getValue(Level.class);
levelList.add(level);
}
/** Attch both "userList" and "levelList" to RecyclerView */
}
#Override
public void onCancelled(DatabaseError error) {
//handle errors
}
});
}
It goes fine.But if there are many nested Listeners, It will hard to read.So I tried to change to RxJava and RxAndroid. Like this-
public Observable<ArrayList<User>> userOb(){
return Observable.create(new
ObservableOnSubscribe<ArrayList<User>>() {
#Override
public void subscribe(final
ObservableEmitter<ArrayList<User>> emitter)
throws Exception {
FirebaseDatabase.getInstance().getReference("Users")
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
ArrayList<UserModel> listUsers;
for(DataSnapshot snapshot: dataSnapshot.getChildren()){
User user = snapshot.getValue(User.class);
listUsers= new ArrayList<>();
listUsers.add(user);
emitter.onNext(listUsers);
}
emitter.onComplete();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
}
Here I don't know how to zip with LevelObservable because levelObservable need UserId from UserObservable to get data from Levels/(uid)/"level_info" .May be this is stupid question but I am new to RxJava. I want to get Corresponding userId from UserObservable to LevelObservable. So how can I do that?
Sorry for my bad English Writing skill.
Edit: Is there some ways to implement like this (because may be I miss some easy ways to implement).
I am making an app where I can upload images to firebase then retrieve them and view them in a viewpager.
The images have a name and an url.
In addition to that, I want to be able to write the name of the image in a textbox and display the corresponding image in an imageview.
This is the code I'm working with :
private void findImage(){
final Query query = mDatabaseRef.orderByChild("name").equalTo(EditTextName.getText().toString());
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot NamedImage : dataSnapshot.getChildren()) {
//i have tried this first but i don't know what method i should use to get the URI from the datasnapshot.
image.setImageURI(NamedImage.getValue());
//then i have tried this but i can't use "context" here, nor can i apply .getImageUrl to the datasnapshot.
Glide.with(context).load(NamedImage.getImageUrl()).into(image);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
I am new to android studio and java and I haven't studied it before starting this application.
Any idea on what I should do please?
I found the solution to my problem :
private void findImage(){
final Query query = mDatabaseRef.orderByChild("name").equalTo(EditTextName.getText().toString());
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot NamedImage : dataSnapshot.getChildren()) {
SliderUtils sliderUtils = NamedImage.getValue(SliderUtils.class);
Glide.with(getApplicationContext()).load(sliderUtils.getImageUrl()).into(image);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
I am retrieving data from firebase database inside for loop , but problem is that firebase functions are not execute synchronously , i know firebase functions are asynchronous . is there any solution for that ?
Code :-
registrationReference.child(userId).child("generated_links").addListenerForSingleValueEvent(new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
peopleModelList.clear();
for(DataSnapshot snapshot : dataSnapshot.getChildren())
{
peopleModel = new PeopleModel();
peopleHashMap =(HashMap)snapshot.getValue();
peopleModel.setChatWith((String)peopleHashMap.get("chatWith"));
peopleModel.setNickname((String)peopleHashMap.get("nickname"));
peopleModel.setChatRoom(snapshot.getKey());
Log.d("kkkk","1st");
if(peopleModel.getChatWith()!=null && !("".equals(peopleModel.getChatWith())))
{
registrationReference.child(peopleModel.getChatWith()).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
peopleModel.setRefresh_token((String)dataSnapshot.child("refresh_token").getValue());
peopleModelList.add(peopleModel);
Log.d("kkkk","2nd");
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Log.d("kkkk","3rd");
}
iCallBackPeople.peopleAct(peopleModelList);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Output :-
1st
3rd
2nd
But i want output like this
1st
2nd
3rd
Note :-
i searched , but never got any solution !
How to get data from Firebase Database in a loop?
Firebase addListenerForSingleValueEvent excute later in loop
I tried this but not worked for me, it is fill my list with last item !
public void listOfUsers(final ICallBackPeople iCallBackPeople) {
count=0;
//peopleModelList = new ArrayList<>();
sortedMap = new TreeMap<>();
// peopleModelList = new ArrayList<PeopleModel>(sortedMap.values());
registrationReference.child(userId).child("generated_links").addListenerForSingleValueEvent(new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// peopleModelList.clear();
for(DataSnapshot snapshot : dataSnapshot.getChildren())
{
peopleModel = new PeopleModel();
peopleHashMap =(HashMap)snapshot.getValue();
peopleModel.setChatWith((String)peopleHashMap.get("chatWith"));
peopleModel.setNickname((String)peopleHashMap.get("nickname"));
peopleModel.setChatRoom(snapshot.getKey());
//Object chatRoom = snapshot.getKey();
Log.d("kkkk","1st");
if(peopleModel.getChatWith()!=null && !("".equals(peopleModel.getChatWith())))
{
addItem(count,iCallBackPeople);
count++;
}
Log.d("kkkk","3rd");
}
Log.d("kkkk","end");
//iCallBackPeople.peopleAct(peopleModelList);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void addItem(final int index, final ICallBackPeople iCallBackPeople) {
registrationReference.child(peopleModel.getChatWith()).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
peopleModel.setRefresh_token((String)dataSnapshot.child("refresh_token").getValue());
Log.d("kkkk","2nd");
sortedMap.put(index, peopleModel);
// sortedMap will sort your list by key (in this case, key is integer)
if(sortedMap.size()==2)
{
peopleModelList = new ArrayList<PeopleModel>(sortedMap.values());
iCallBackPeople.peopleAct(peopleModelList);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
I tried this but not getting all of the item only getting list with last item in snapshot
public void listOfUsers(final ICallBackPeople iCallBackPeople) {
peopleModelList = new ArrayList<>();
registrationReference.child(userId).child("generated_links").addListenerForSingleValueEvent(new ValueEventListener()
{
PeopleModel peopleModel;
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
peopleModelList.clear();
for(final DataSnapshot snapshot : dataSnapshot.getChildren())
{
peopleModel = new PeopleModel();
peopleHashMap =(HashMap)snapshot.getValue();
peopleModel.setChatWith((String)peopleHashMap.get("chatWith"));
peopleModel.setNickname((String)peopleHashMap.get("nickname"));
peopleModel.setChatRoom(snapshot.getKey());
if(peopleModel.getChatWith()!=null && !("".equals(peopleModel.getChatWith())))
{
getToken(new CallBackGetToken() {
#Override
public void token(String token) {
peopleModel.setRefresh_token(token);
Toast.makeText(context, token, Toast.LENGTH_SHORT).show();
peopleModelList.add(peopleModel);
//here i am checking my peopleModelList size is equal or not to snapshot
if(peopleModelList.size()==2)
iCallBackPeople.peopleAct(peopleModelList);
}
},peopleModel);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void getToken(final CallBackGetToken callBackGetToken ,PeopleModel peopleModel) {
registrationReference.child(peopleModel.getChatWith()).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
callBackGetToken.token((String)dataSnapshot.child("refresh_token").getValue());
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
I think you should pass through an interface(create one and implement at this class). the method inside the interface should have a string as a parameter (it will receive your peopleModel.getChatWith() ) .
Inside your if(peopleModel.getChatWith()!=null && !("".equals(peopleModel.getChatWith())))you should request your interface.
I think is a solution for your asynchronously question.
Here is my solution:
int count =0;
SortedMap<Integer,PeopleModel> sortedMap;
private void set() {
count =0;
registrationReference.child(userId).child("generated_links").addListenerForSingleValueEvent(new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
peopleModelList.clear();
sortedMap = new TreeMap<>();
for(DataSnapshot snapshot : dataSnapshot.getChildren())
{
peopleModel = new PeopleModel();
peopleHashMap =(HashMap)snapshot.getValue();
peopleModel.setChatWith((String)peopleHashMap.get("chatWith"));
peopleModel.setNickname((String)peopleHashMap.get("nickname"));
peopleModel.setChatRoom(snapshot.getKey());
Log.d("kkkk","1st");
if(peopleModel.getChatWith()!=null && !("".equals(peopleModel.getChatWith())))
{
addItem(count);
count++;
}
Log.d("kkkk","3rd");
}
iCallBackPeople.peopleAct(peopleModelList);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void addItem(final int index) {
registrationReference.child(peopleModel.getChatWith()).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
peopleModel.setRefresh_token((String)dataSnapshot.child("refresh_token").getValue());
Log.d("kkkk","2nd");
sortedMap.put(index, peopleModel);
// sortedMap will sort your list by key (in this case, key is integer)
// you can get peopleModelList = new ArrayList<>(sortedMap.values);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Maybe I'm over simplifying it, but I feel like you should just use simple recursion.
List<People> peopleList;
int currentIndex = 0
private void myFirebaseMethodAction(person){
registerListener.onCallbacks(new ValueListener(){
onDataChanged(){
person.addStufforDoStuff();
if(peopleList.size > currentIndex + 1){
myFirebaseMethodAction(peopleList.get(++currentIndex)
}
}
onFailed(){
//handle it
}
}
}
Does that make sense?
Just saying walk the list with an index, simple.
btw above is pseduo code, don't copy verbatim lol.
This loop is fetching 1 key at a time. I want to store all the keys in String[] basically at the end of loop and then use it in ArrayAdapter for auto complete text view.
fdatabaseuser.addValueEventListener(new ValueEventListener({
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String item="";
for (DataSnapshot list: dataSnapshot.getChildren())
{
Object obj= list.getKey();
item=obj.toString();
}
Toast.makeText(GiveActivity.this,item,Toast.LENGTH_LONG).show();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Actually you already have the keys. You can create an ArrayList and add items.
ArrayList<String> keys = new ArrayList<>();
fdatabaseuser.addValueEventListener(new ValueEventListener({
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String item="";
for (DataSnapshot list: dataSnapshot.getChildren())
{
Object obj= list.getKey();
item=obj.toString();
keys.add(item);
}
Toast.makeText(GiveActivity.this,item,Toast.LENGTH_LONG).show();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
List<String> item;
Initialise list in the OnCreate Method
item=new ArrayList<>();
Then change this code:
fdatabaseuser.addValueEventListener(new ValueEventListener({
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot list: dataSnapshot.getChildren())
{
Object obj= list.getKey();
item.add(obj.toString();)
}
Toast.makeText(GiveActivity.this,item,Toast.LENGTH_LONG).show();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
To achieve this, please use the following code:
fdatabaseuser.addValueEventListener(new ValueEventListener({
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<String> list = new ArrayList<>();;
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String key = ds.getKey();
list.add(key);
}
Log.d("TAG", list);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
Remember, the list must be declared and updated inside the onDataChange() method, otherwise it will be null, due the asynchronous behaviour of onDataChange() which is called even before you are adding those keys to the list.
Hello Everyone I am using firebase database in my app. I am able to add data to database. Now I want to implement search in my app, I have two option for search users,
1)Blood Group
2)User Area
I am able to get data as per blood group selection, but I don't know how can I fetch data with blood group and area. (Multiple Selection Filter)
Now if the user will select 'A+' as blood group from spinner and select Area 'ABC'
Then result would come as Users with 'A+' blood group and 'ABC' area.
search_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.println("Default Selected"+sel_blood_group);
mFirebaseDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Your Logic here
for (DataSnapshot eventSnapshot : dataSnapshot.getChildren()) {
UserRegisterModel mModel = eventSnapshot.getValue(UserRegisterModel.class);
// Log.e("DATA" ,""+ mModel.getName());
}
Query chatRoomsQuery = mFirebaseDatabase.orderByChild("blood_group").equalTo(sel_blood_group);
chatRoomsQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
// dataSnapshot is the "issue" node with all children with id 0
for (DataSnapshot issue : dataSnapshot.getChildren()) {
// do something with the individual "issues"
UserRegisterModel mModel = issue.getValue(UserRegisterModel.class);
Log.e("QUERY DATA" ,""+ mModel.getName());
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Log.e("DATA" ,""+ chatRoomsQuery.toString());
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
Firebase RealTime Database does not support multiple where clauses. So try to query with one filter and then filter the next one programatically.
search_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.println("Default Selected"+sel_blood_group);
System.out.println("Default Selected"+sel_area);
mFirebaseDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Your Logic here
for (DataSnapshot eventSnapshot : dataSnapshot.getChildren()) {
UserRegisterModel mModel = eventSnapshot.getValue(UserRegisterModel.class);
// Log.e("DATA" ,""+ mModel.getName());
}
Query chatRoomsQuery = mFirebaseDatabase.orderByChild("blood_group").equalTo(sel_blood_group);
chatRoomsQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
// dataSnapshot is the "issue" node with all children with id 0
for (DataSnapshot issue : dataSnapshot.getChildren()) {
// do something with the individual "issues"
UserRegisterModel mModel = issue.getValue(UserRegisterModel.class);
if(mModel.getArea().equals(sel_area))
Log.e("QUERY DATA" ,""+ mModel.getName());
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Log.e("DATA" ,""+ chatRoomsQuery.toString());
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});enter code here
You can make userName to be added only once using the following method. I have assumed that you are storing the user details in UserRegisterModel class. Please take care of the DatabaseReferences as I have used what you have mentioned and I am not aware of your Database structure.
Query chatRoomsQuery = mFirebaseDatabase.orderByChild("User_Name").equalTo(userRegisterModel.getUserName());
chatRoomsQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
Log.e("UserAlready Registered");
}
else
{
mFirebaseDatabase.push().setValue(userRegisterModel);;
Log.i("User added Successfully");
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
I have not tested the code but I think it will work! :)