I was Trying to add childs(Programmes) to the Above reference STUDENTS.
So the issue is when I retrieve the keys and add them to the ArrayList of Strings.
And check Whether it Matches the entered Text it gives ;
Like Example; in the photo, we have Three Programmes bps,cs,mm.
it gives me matches, not matches,not matches result
what I want is whether it matches or not like as above.
CODE
// retreiving the edittext to String
String prnamez = programmeName.getEditableText().toString().trim().toLowerCase();
// checking if the program already exists
FirebaseAuth autha = FirebaseAuth.getInstance();
DatabaseReference dnn = FirebaseDatabase.getInstance()
.getReference("Admin").child(autha.getUid()).child("INSTITUTE")
.child("STUDENTS");
// arraylist to add the keys of the programme
ArrayList<String> pgName = new ArrayList<>();
// value event listener
dnn.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.exists()) {
progressBar.setVisibility(View.VISIBLE);
// going through all the keys and adding them to the arraaylist of pgName
for (DataSnapshot regis : snapshot.getChildren()) {
// retrieved the programme Name
pgName.add(regis.getKey().toString());
}
// going through the lenght of the array list
for (int i = 0; i < pgName.size(); i++) {
// if the entered programme matches already existing programme name
// then show this custom Toast
if (pgName.get(i).equals(prnamez)) {
// custom Toast
StyleableToast.makeText(Programme_students.this,
"Matches", R.style.exampleToast).show();
} else {
StyleableToast.makeText(Programme_students.this,
"not Matches", R.style.exampleToast).show();
// WANT TO ADD NEW PROGRAMME IN THIS CASE
}
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
});
Related
This question already has answers here:
Duplicate objects from Firebase loaded into ListView
(2 answers)
Closed 1 year ago.
I am trying to add the teacher to the firebase real-time DB and Retrieving the teachers in the listView as shown in this image:
But when add a new item I get retrieved the existing data twice and new data once as shown in the picture below:
After Adding - Leading the Duplication of the ListView
''' //value variables
ArrayList<teachersHelper> teachersFromdatabase = new ArrayList<>();
teacher_adapter teacher_adapter;
THIS METHOD IS CALLED ON ONCLICK OF ADDTEACHERS
private void addingteacher() {
progressBar.setVisibility(View.VISIBLE);
// opening the Custom dialog to get the information of the new Teachers
Dialog mydialog = new Dialog(teacher_admin.this);
mydialog.setContentView(R.layout.addteachers);
mydialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
progressBar.setVisibility(View.GONE);
mydialog.show();
mydialog.setOnDismissListener(dialog -> progressBar.setVisibility(View.GONE));
// hooking all the views of the dialog
EditText teache5rName = mydialog.findViewById(R.id.teacherssname_dialogbox);
EditText registrationNumber = mydialog.findViewById(R.id.teachersReg_dialogbox);
EditText passwordteacher = mydialog.findViewById(R.id.teacherspassword_dialogbox);
EditText department = mydialog.findViewById(R.id.teachersDepartment_dialogbox);
EditText mobilenumber = mydialog.findViewById(R.id.teacherMobilenumber_dialogbox);
NeumorphButton addteachersButton = mydialog.findViewById(R.id.add_teachersDialog);
// when the add button on the dialog is pressed
addteachersButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// dilog and progress bar
progressBar.setVisibility(View.VISIBLE);
//converting the edittext the String Literals
String tnamez = teache5rName.getEditableText().toString().trim();
String tregNu = registrationNumber.getEditableText().toString().trim();
String tpassw = passwordteacher.getEditableText().toString().trim();
String tdepartment = department.getEditableText().toString().trim();
String tmobileNum = "+91" + mobilenumber.getEditableText().toString().trim();
// validating the fields wheather they are empty or not
if (!validateFields(tnamez, tregNu, tpassw, tdepartment, tmobileNum)) {
// if empty then show a error custom dialog
donedialogboxMeathod(false);
progressBar.setVisibility(View.GONE);
return;
}
donedialogboxMeathod(true);
// where the teachers are under so the adding teacher fuction is in admin so
// adminhelper is created and called the function
AdminHelper adminHelper = new AdminHelper();
// adding the teacher
adminHelper.addTEachers(tnamez, tregNu, tpassw, "No", tdepartment,
"No", tmobileNum, "No");
// notifyin the adpater that we added new ber
teacher_adapter.notifyDataSetChanged();
// dissmissing the progressbar and Custom dialog
progressBar.setVisibility(View.GONE);
mydialog.dismiss();
}
});
THIS METHOD IN ADMINHELPER TO ADDTEACHERS
public teachersHelper addteacher(String tName, String tregNumber, String tPassword,String
imageId, String tDepartment,String tEmail, String
tphoneNumber, String tadress) {
// creating the teachers Helper Class
teachersHelper teachersHelpers = new teachersHelper(tName, tregNumber, tPassword, imageId, tDepartment,
tEmail, tphoneNumber, tadress);
// database stuff
DatabaseReference teacherreferenc = FirebaseDatabase.getInstance().
getReference("Admin").child(mAuth.getUid()).child("INSTITUTE");
//adding value
teacherreferenc.child("TEACHERS").child(tregNumber).setValue(teachersHelpers);
return teachersHelpers;
}
RETRIEVING THE TEACHERS AND ADDING THEM TO THE LISTVIEW (i think the problem is here)
public void settingViews(){
// Firebase variables to retreive the data of the teacher
FirebaseAuth mAuth = FirebaseAuth.getInstance();
DatabaseReference databasereference = FirebaseDatabase.getInstance()
.getReference("Admin").child(mAuth.getUid()).child("INSTITUTE")
.child("TEACHERS");
//the teachers are stored with the node of registrationNumber so i created a arraylist
ArrayList<String> registrattionNumber = new ArrayList<>();
// valueevent to retreving the data
databasereference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
// cheching if the snapshot exists
if (snapshot.exists()) {
// getting all the registration Number
for (DataSnapshot regis : snapshot.getChildren()) {
// adding the registrationNumbers to the arraylist
registrattionNumber.add(regis.getKey());
}
// based on the arraylist of the registrationNUmber we will be retriving
// the data of teachers of particular registrartion Number
for (int i = 0; i < registrattionNumber.size(); i++) {
//firebase stuff
Query teacherssdata = FirebaseDatabase.getInstance()
.getReference("Admin").child(mAuth.getUid()).child("INSTITUTE")
.child("TEACHERS").child(registrattionNumber.get(i));
// value evnet listener
teacherssdata.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.exists()) {
// retreiving all the teachers data from the snapshot
String _name = snapshot.child("tName").getValue().toString();
String _regno = snapshot.child("tregNumber").getValue().toString();
String _pass = snapshot.child("tPassword").getValue().toString();
String _img = snapshot.child("image").getValue().toString();
String _depart = snapshot.child("tDepartment").getValue().toString();
String _phonenumber = snapshot.child("tphoneNumber").getValue().toString();
String _adress = snapshot.child("tadress").getValue().toString();
String _emai = snapshot.child("tEmail").getValue().toString();
// creating the teacherclass and adding all the info from the firebase
teachersHelper teachersHelperzzzz = new
teachersHelper(_name, _regno, _pass, _img, _depart, _emai
, _phonenumber, _adress);
// adding the teacher objects to the Golbal Variable
teachersFromdatabase.add(teachersHelperzzzz);
// creating listview
// creating the adapter
teacher_adapter = new teacher_adapter(teacher_admin.this,
teachersFromdatabase);
// setting the adapter to the listview
listView.setAdapter(teacher_adapter);
progressBar.setVisibility(View.GONE);
} else {
progressBar.setVisibility(View.VISIBLE);
StyleableToast.makeText(teacher_admin.this, "Deleted Sucessfully"
, R.style.exampleToast).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
dialogboxMeathod(teacher_admin.this, error.getMessage());
}
});}
Every time there's a change to databasereference, your onDataChange gets called with a full snapshot of the data at that path. So even if only one child node was changed/added/removed, the snapshot also contains all other (unmodified) child nodes that you already added to registrattionNumber.
The simplest solution is to clear registrattionNumber at the top of onDataChange:
databasereference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
registrattionNumber.clear();
...
Also see:
Duplicate objects from Firebase loaded into ListView
Duplicate data from firebase realtime databse
Item gets duplicated in adapter, when we delete or update item from Firebase Realtime Database
Why do i get duplicate values when adding data to firebase realtime database using kotlin?
And many more from this search: https://stackoverflow.com/search?q=%5Bfirebase-realtime-database%5D%5Bandroid%5D+duplicate
In my Firebase database, I have two children let Child1, Child2. Child1 contains profile information of users as Root/Child1/Uid-User(x)/User_details. Child2 contains transactions done by users as Root/Child2/Uid-User(x)/Transaction_details. I want to retrieve user profile info of one user then transaction of the same user then store it in some object. Then profile info of another user, his transaction and store it in another object and so on.
How can I do that? as Firebase methods run asynchronously so if I create one method to retrieve from Child1 and another for Child2 then they execute asynchronously and create the problem.
You can retrieve it Initially by putting a listener to the userDetail node once this is done ensure retrieved data should not be null after again you make another request to retrive his transction data
Or You Retrieve the both separately and put the result into a 2 HashMap once the data retrieved from both listeners you can merge them based on the key (Ensure that the length of both map should be same)
To ensure Both the listeners are invoked you make like this
Initially put two variables
userProfileHit = 0;
userTransctionHit = 0;
privte void userList () {
userProfileHit ++;
private ValueEventListener userListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//retriveData
userProfileHit --;
doMergingTask ();
}
#Override
public void onCancelled(DatabaseError databaseError) {
userProfileHit --;
doMergingTask ()
}
};
}
private void transctionList () {
userTransctionHit ++;
private ValueEventListener transctionListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
userTransctioneHit --;
doMergingTask ()
}
#Override
public void onCancelled(DatabaseError databaseError) {
userTransctionHit --;
doMergingTask ()
}
};
}
private void doMergingTask () {
if (userTransctionHit == 0 && userProfileHit == 0) {
// Check Datas are valid and merge it
}
}
My suggestion is that you put the method for retrieving the users transactions inside the onDataChanged method for retrieving profile information. So that, when you get the users profile information, you use it to get users transaction information and create the object. You can nest the firebase event listeners to produce the any outcome you want.
For Example:
final FirebaseDatabase database = FirebaseDatabase.getInstance();
final DatabaseReference ref = database.child("profile");
// Attach the first listener to read the data at our profile reference
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
final Profile profile = dataSnapshot.getValue(Profile.class);
DatabaseReference transactionRef = database.child("transaction");
// Attach a listener to read the data at our transactions reference
transactionRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Transaction transaction = dataSnapshot.getValue(Transaction.class);
//
//Do stuff with the Transaction object and Profile object here.
//
}
#Override
public void onCancelled(DatabaseError databaseError) {
System.out.println("The read failed: " + databaseError.getCode());
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
System.out.println("The read failed: " + databaseError.getCode());
}
});
Here member’s key in Group is User’s key.
Task: Want to fetch comida_id froenter code herem User based on Group’s member key.
Here we are trying to first fetch member keys from Group. While fetching member key we also want to fetch User and User’s comida_id while that member’s loop is going. So the scenario will be First we are going to fetch all keys from Group based on Group’s key ( for example createTime, groupName, members ). Now from that we will execute loop on members so will get member’s key. Now while fetching this member’s key in that loop, we want to fetch comida_id from User’s, which will be fetch in that loop only.
GroupKey -> get Data(createTime, groupName, members, restaurants) -> fetch members key and comida_id ( in Loop (get member key then fetch comida_id ))
*My Code
FirebaseDatabase mDatabase_gp = FirebaseDatabase.getInstance();
mDatabase_gp.getReference("Group/"+group_key).addValueEventListener(
new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
Map<String, Object> valuesMap = (HashMap<String, Object>) dataSnapshot.getValue();
Map userkey = (Map) valuesMap.get("members");
Log.d("Members", String.valueOf(userkey));
for (Object ke: userkey.keySet())
{
Log.d("runfirst","First Run");
String key = String.valueOf(ke.toString());
Log.d("Member key",key);
// HERE WHAT CORRESPONDS TO JOIN
FirebaseDatabase User = FirebaseDatabase.getInstance();
User.getReference("User/"+key).addValueEventListener(
new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
Map<String, Object> valuesMap = (HashMap<String, Object>) dataSnapshot.getValue();
String userid = String.valueOf(valuesMap.get("comida_id"));
Log.d("comida_id",userid);
Toast.makeText(ChatSectionActivity.this,userid,Toast.LENGTH_SHORT).show();
}
#Override
public void onCancelled(DatabaseError databaseError)
{
}
}
);
}
Log.d("runlast","Last Run");
}
#Override
public void onCancelled(DatabaseError databaseError)
{
}
}
);
*
In Above code we tried to achieve same thing but here this code will fetch all member keys from group first. After fetching all members it will fetch comida_ids in another loop.. So there will be like two different loops working to fetch comida_id from members. It’s not working like join query.
GroupKey -> get Data(createTime, groupName, members, restaurants) -> fetch members key (in Loop (get member key) after then fetch comida_id .
*1) I was try this solution - How to perform join query in Firebase?
**But get this error –
Incompatible types.
Required: com.google.firebase.database.DatabaseReference
Found: com.google.firebase.database.ValueEventListener
https://i.stack.imgur.com/ljlWo.png
Firebase doesn't have join queries. And what you are doing wrong is your are referencing your data base on Fireabaseuser, which is wrong.
mdatabaseReference.child("Answer").child("Answer"+QID).orderByChild("questionId").equalTo(QID).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (muftiAnswer_List.size() > 0)
muftiAnswer_List.clear();
for (DataSnapshot postsnapshot : dataSnapshot.getChildren()) {
final AnswerClass muftiAnswer = postsnapshot.getValue(AnswerClass.class);
String ide=muftiAnswer.getMuftiId(); //getting AlimId From Class object
Log.e(TAG, "Alim:"+ muftiAnswer.getMuftiId());
//Using Query to get Alim Name From Data Table.!
mdatabaseReference.child("users").child("Alim").child(ide).addListenerForSingleValueEvent(new ValueEventListener() {
#Override //.orderByChild("alimId").equalTo(user_Id)
public void onDataChange(DataSnapshot dataSnapshot) {
Log.e(TAG, "AlimNode:");
for(DataSnapshot postSnapshot:dataSnapshot.getChildren())
{
Log.e(TAG, "EqualNode:");
if(postSnapshot.getKey().equals("alimName"))
{
Log.e(TAG, "AlimNameNodeSnapShot:");
//Setting Alim Name in Current Object replcing id for name
muftiAnswer.setMuftiId(postSnapshot.getValue().toString());
}
// resultMuftiAnswer_List.add(muftiAnswer);
}//End of snapshot
}//ondata Change
#Override
public void onCancelled(DatabaseError databaseError) {
// Failed to read value
Log.w(TAG, "Failed to read value.", databaseError.toException());
}
});//End OF Alim Query
}//end of comments
circular_progress2.setVisibility(View.GONE);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(Details_Activity.this, "LOLOLOL", Toast.LENGTH_SHORT).show();
}
});
You have to use nested loops for doing joins like MYSQL
Query query = reference.child("issue").orderByChild("id").equalTo(0);
query.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"
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Visit link for better understanding
https://firebase.googleblog.com/2013/10/queries-part-1-common-sql-queries.html
So I have a list of objects stored in firebase and want to query for just one object using child equal to method but I am getting a map with single key value instead.
Code below showing what I want to achieve instead of dealing with hashmaps.
final FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference coutryRef = database.getReference(FireContract.PATH_COUNTRY);
Query countryQuery = coutryRef.orderByChild(FireContract.CHILD_NAME)
.equalTo(TestUtilities.TEST_COUNTRY_ALGERIA).limitToFirst(1);
countryQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Country country = dataSnapshot.getValue(Country.class);
assertEquals(TestUtilities.TEST_COUNTRY_ALGERIA, country.getName());
//get country key
String coutryKey = dataSnapshot.getKey();
}
#Override
public void onCancelled(DatabaseError databaseError) {
fail("Failed to get country: " + databaseError.getMessage());
}
});
When you fire a query, you will always get a list of results. Even when there is only a single item matching the query, the result will be a list of one item.
To handle the list, you can either use a ChildEvenListener or you can loop over the children in your ValueEventListener:
countryQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot countrySnapshot: dataSnapshot.getChildren()) {
Country country = countrySnapshot.getValue(Country.class);
assertEquals(TestUtilities.TEST_COUNTRY_ALGERIA, country.getName());
//get country key
String countryKey = countrySnapshot.getKey();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
fail("Failed to get country: " + databaseError.getMessage());
}
});
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.