I'm making a Quizz app and I have the questions and the answers in Realtime Database,
I have no problem displaying the information in the recyclerview, this recycler view is composed of a radio group of 3 radio buttons,
I need to compare the radio button with the record of the correct answer in realtime database.
btnacab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
database.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if(corregido == false){
//for(DataSnapshot dataSnapshot : snapshot.getChildren()){
int cont = 1;
String p = "p";
npreg = p + cont;
corregirpregunta("Enfermeria", "p1");
corregido = true;
btnacab.setText("SALIR");
cont++;
// }
}else{
Intent i = new Intent(ModeloExamen3.this, GeneralTest.class);
startActivity(i);
}
myAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
pauseTimer();
}
});
*/
}
public void corregirpregunta(String tipo, String npreg){
database.child(tipo).child(npreg).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
PreguntaExamen pregunta = snapshot.getValue(PreguntaExamen.class);
if(pregunta != null){
String corr = pregunta.getCorrecta();
int n = Integer.parseInt(corr.toString());
RadioButton rbselected = findViewById(rgrex.getCheckedRadioButtonId());
int nresp = rgrex.indexOfChild(rbselected) +1 ;
if(nresp == n){
puntuacion++;
tvpuntu.setText("PuntuaciĆ³n: " + puntuacion+"/10");
}
resp1.setTextColor(Color.RED);
resp2.setTextColor(Color.RED);
resp3.setTextColor(Color.RED);
switch (n){
case 1:
resp1.setTextColor(Color.GREEN);
break;
case 2:
resp2.setTextColor(Color.GREEN);
break;
case 3:
resp3.setTextColor(Color.GREEN);
break;
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
The method to correct a single question works well, the problem is to make a loop so that a single method corrects all the questions that are shown in the recyclerview.
I'm developing an android application for college project using Java and Firebase. I want to store the details of faculties working in college like name,email,department etc based on their position. I have created 3 child nodes HOD,Class mentor and lecturers inside Faculties as you can see that in here.
my problem is when I want to add the members inside any one these child I want to check if that members email ID is exist in any other childs. For example I want to add a member in HOD child.If this members email existed inside Lecturers child it should display Toast user already existed as Lecturer else it should add member inside Lecturer.
I used this code.
post = "HOD";
databaseReference.child(post).orderByChild("email").equalTo(email).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
Toast.makeText(MainActivityAddFaculty.this, "User already exist in "+post, Toast.LENGTH_SHORT).show();
} else {
post = "Class mentor";
databaseReference.child(post).orderByChild("email").equalTo(email).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
Toast.makeText(MainActivityAddFaculty.this, "User already exist in "+post, Toast.LENGTH_SHORT).show();
} else {
post = "Lecturer";
databaseReference.child(post).orderByChild("email").equalTo(email).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
Toast.makeText(MainActivityAddFaculty.this, "User already exist in "+post, Toast.LENGTH_SHORT).show();
} else {
checkData();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(MainActivityAddFaculty.this, databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(MainActivityAddFaculty.this, databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(MainActivityAddFaculty.this, databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
It works fine but it's lengthy and also it takes time to check.If there is any better solution that would be very helpful.
This is is my code complete code for adding Faculties.
public class MainActivityAddFaculty extends AppCompatActivity {
private TextInputLayout addName, addEmail;
private TextInputEditText addEditName, addEditEmail;
private Button addBtn;
private Spinner addPositionSpinner,addDeptSpinner,addYearSpinner;
private TextView addPosition,addDept,addYear;
private String sDept = "Select department",sPost = "Select position",sYear = "Select year";
private String position,department,year,post;
private boolean b = false;
private FirebaseDatabase firebaseDatabase;
private FirebaseStorage firebaseStorage;
private DatabaseReference databaseReference,databaseReference2;
private StorageReference storageReference;
LoadingDialog loadingDialog;
private String facultyID;
private String name,email;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_faculty);
setTitle("Add Hod");
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
addName = findViewById(R.id.addFName);
addEmail = findViewById(R.id.addFEmail);
addEditName = findViewById(R.id.addFEditName);
addEditEmail = findViewById(R.id.addFEditEmail);
addBtn = findViewById(R.id.addFBtn);
addPositionSpinner = findViewById(R.id.addFPositionSpinner);
addPosition = findViewById(R.id.addFPosition);
addDeptSpinner = findViewById(R.id.addFDepartmentSpinner);
addDept = findViewById(R.id.addFDepartment);
addYearSpinner = findViewById(R.id.addFYearSpinner);
addYear = findViewById(R.id.addFYear);
addDeptSpinner.setVisibility(View.GONE);
addYearSpinner.setVisibility(View.GONE);
addDept.setVisibility(View.GONE);
addYear.setVisibility(View.GONE);
firebaseDatabase = FirebaseDatabase.getInstance();
databaseReference = firebaseDatabase.getReference("FACULTIES");
facultyID = databaseReference.push().getKey();
loadingDialog = new LoadingDialog(MainActivityAddFaculty.this);
//selectPosition();
//TODO:Select position
List<String> categories = new ArrayList<>();
categories.add(0,"Select position");
categories.add("HOD");
categories.add("Class mentor");
categories.add("Lecturer");
ArrayAdapter<String> dataAdapter;
dataAdapter = new ArrayAdapter(this,android.R.layout.simple_spinner_item,categories);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
addPositionSpinner.setAdapter(dataAdapter);
addPositionSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
addPosition.setText(parent.getSelectedItem().toString());
test();
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
Toast.makeText(MainActivityAddFaculty.this, "Select a position", Toast.LENGTH_SHORT).show();
}
});
addBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
name = addEditName.getText().toString().trim();
email = addEditEmail.getText().toString().trim();
if (TextUtils.isEmpty(name)) {
Toast.makeText(MainActivityAddFaculty.this, "Enter name", Toast.LENGTH_SHORT).show();
}else {
if (TextUtils.isEmpty(email)) {
Toast.makeText(MainActivityAddFaculty.this, "Enter email.", Toast.LENGTH_SHORT).show();
} else {
checkData();
}
}
}
});
}
private void test(){
position = addPositionSpinner.getSelectedItem().toString();
if (position.equals(sPost)){
addDeptSpinner.setVisibility(View.GONE);
addYearSpinner.setVisibility(View.GONE);
addDept.setVisibility(View.GONE);
addYear.setVisibility(View.GONE);
}else if (position.equals("HOD")){
addDeptSpinner.setVisibility(View.VISIBLE);
addYearSpinner.setVisibility(View.GONE);
addDept.setVisibility(View.VISIBLE);
addYear.setVisibility(View.GONE);
} else if (position.equals("Class mentor")){
addDeptSpinner.setVisibility(View.VISIBLE);
addDept.setVisibility(View.VISIBLE);
addYearSpinner.setVisibility(View.VISIBLE);
addYear.setVisibility(View.VISIBLE);
} else if (position.equals("Lecturer")){
addDeptSpinner.setVisibility(View.GONE);
addYearSpinner.setVisibility(View.GONE);
addDept.setVisibility(View.GONE);
addYear.setVisibility(View.GONE);
} else {
addDeptSpinner.setVisibility(View.GONE);
addYearSpinner.setVisibility(View.GONE);
addDept.setVisibility(View.GONE);
addYear.setVisibility(View.GONE);
}
}
private void checkData(){
position = addPositionSpinner.getSelectedItem().toString();
department = addDeptSpinner.getSelectedItem().toString();
year = addYearSpinner.getSelectedItem().toString();
if (position.equals(sPost)){
Toast.makeText(this, "Select position", Toast.LENGTH_SHORT).show();
} else if (position.equals("HOD")){
if (department.equals(sDept)){
Toast.makeText(MainActivityAddFaculty.this, "Select department.", Toast.LENGTH_SHORT).show();
} else {
AddHOD addHOD = new AddHOD(name,position,department,email,facultyID);
databaseReference.child(position).child(facultyID).setValue(addHOD).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(MainActivityAddFaculty.this, "Faculty added successfully", Toast.LENGTH_SHORT).show();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(MainActivityAddFaculty.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}else if (position.equals("Class mentor")){
//add Class mentor process started
if (!department.equals(sDept)){
if (!year.equals(sYear)) {
AddClassMentor addClassMentor = new AddClassMentor(name, position, department, year, email, facultyID);
databaseReference.child(position).child(facultyID).setValue(addClassMentor).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(MainActivityAddFaculty.this, "Faculty added successfully", Toast.LENGTH_SHORT).show();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(MainActivityAddFaculty.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}else {
Toast.makeText(this, "Select year.", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "Select department", Toast.LENGTH_SHORT).show();
}
} else if (position.equals("Lecturer")){
AddLecturer addLecturer = new AddLecturer(name,position,email,facultyID);
databaseReference.child(position).child(facultyID).setValue(addLecturer).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(MainActivityAddFaculty.this, "Faculty added successfully", Toast.LENGTH_SHORT).show();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(MainActivityAddFaculty.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
} else {
Toast.makeText(this, "Entry is pending.", Toast.LENGTH_SHORT).show();
}
}
}
Firebase's queries work on a list of nodes. Since you have a hierarchy, you'll need to fire the same query for each list you have in there, as you're doing today.
As usual when dealing with NoSQL databases, the solution is to model the data in a way that makes the use-case easiest. If you want to search across all members, store a single list of members:
"members": {
"$memberid": {
"email": "membersemail#institute.edu",
"memberType": "Class mentor" // or "HOD" or "Lecturer"
}
}
With the above structure you only have to execute one query to find all members with a specific email address.
You can either use the above structure to replace the three structures you currently have, or you can use it as an additional structure just for this use-case. Which one to choose depends on the other use-cases in your app, there is no solution that is right for all apps, just the one that works for you.
Enforcing uniques across values as you're doing here, will lead to scalability issues over time, as you:
Need to search across all members, which takes more time as you get more members.
More importantly: you will need to use a transaction to insert new users, to reduce the chances that multiple users claim the same email address at the same time.
This leads to a second scaling problem, as you'll need to run that transaction on the evert-growing /members node.
Finally: a malicious user can bypass the transaction by writing their own code, and still claim any email address.
Ensuring uniqueness on Firebase is only really enforceable if you use those values as the key in a list, so by maintaining a (additional) list of email addresses.
For more on this see:
Firebase security rules to check unique value of a child #AskFirebase
Firebase android : make username unique
How do you prevent duplicate user properties in Firebase?
Firebase realtime database validation username and email
I am trying to execute this if statement so the value 'Like' with the unique id is written to the database twice. The line of code is:
mDatabaseChemRef.child(uploadCurrent.getNumber()).child(mAuth.getCurrentUser().getUid()).setValue("Like");
and the database is stored like so:
{
"467" : {
"4ulBYMRcP4WbhTCFXHSTNwX2yPU2" : "Like"
}
}
So essentially I want the "Like" along side the same unique ID to be written twice rather than once. Below is the full code. So when the user clicks the like button I want it to like twice rather than once is there a way to write this line twice?
holder.mLikebtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mProcessTechLike = true;
mDatabaseTechRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if(uploadCurrent.getCategory().equals("Technology")) {
if (mProcessTechLike) {
if (dataSnapshot.child(uploadCurrent.getNumber()).hasChild(mAuth.getCurrentUser().getUid())) {
//delete like
dataSnapshot.child(uploadCurrent.getNumber()).child(mAuth.getCurrentUser().getUid()).getRef().removeValue();
mProcessTechLike = false;
Toast.makeText(mContext, "Vote Retracted", Toast.LENGTH_LONG).show();
holder.mLikebtn.setColorFilter(null);
} else {
Resources res = mContext.getResources();
final int newColor = res.getColor(R.color.new_color);
holder.mLikebtn.setColorFilter(newColor, Mode.SRC_ATOP);
mDatabaseTechRef.child(uploadCurrent.getNumber()).child(mAuth.getCurrentUser().getUid()).setValue("Like");
mProcessTechLike = false;
Toast.makeText(mContext, "Vote Counted", Toast.LENGTH_LONG).show();
}
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
I am facing a problem of how to exactly use Firebase Transaction runTransaction() method. Here when the user clicks the button I am trying to fetch the value from database and increment it and then again send it back to database. Now issue is what if multiple users tap the button at the same time, for this I am using Firebase transaction. But don't know exactly how to write the code. Here is the code which I have tried but not working. I just want to update the value from 0 to 1, if button is clicked by only one user and if clicked simultaneously by many users, then one of the user should wait until the first user completes the updating.
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(final DataSnapshot dataSnapshot) {
final String mainValue = (String) dataSnapshot.child("values").child("number").getValue();
btnInc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
myRef.runTransaction(new Transaction.Handler() {
#Override
public Transaction.Result doTransaction(final MutableData mutableData) {
mutableData.child("number").setValue(String.valueOf(Integer.parseInt(mainValue) + 1));
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
Toast.makeText(MainActivity.this, "Result: "+b, Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, "Error: "+databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
Here is my database screenshot
I am trying to load data from firebase database and then I want to add some more data to it and in the end I want it to upload back. But the problem is when the data is being uploaded back it is not stopping after updating the data. It looks like it is under loop and doing the task again and again.
mTempDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.hasChild(mAuth.getCurrentUser().getUid())){
final DatabaseReference newTemp = mTempDatabase.child(mAuth.getCurrentUser().getUid());
final long qntCount = (long) dataSnapshot.child(mAuth.getCurrentUser().getUid()).child("QuantityCount").getValue();
final long foodamount = (long) dataSnapshot.child(mAuth.getCurrentUser().getUid()).child("QuantityCount").getValue();
//final long countfood = (long) dataSnapshot.child(mAuth.getCurrentUser().getUid()).child("QuantityCount").getValue();
mDatabaseBestseller.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String foodname = (String) dataSnapshot.child(food_key).child("foodname").getValue();
long foodprice = (long) dataSnapshot.child(food_key).child("foodprice").getValue();
long mfoodprice = foodprice + foodamount;
long mqntCOunt = qntCount +1;
newTemp.child("QuantityCount").setValue(mqntCOunt);
newTemp.child("FoodPrice1").setValue(mfoodprice);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
mTempDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(!dataSnapshot.hasChild(mAuth.getCurrentUser().getUid())) {
final DatabaseReference newTemp = mTempDatabase.child(mAuth.getCurrentUser().getUid());
mDatabaseBestseller.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String foodname = (String) dataSnapshot.child(food_key).child("foodname").getValue();
long foodprice = (long) dataSnapshot.child(food_key).child("foodprice").getValue();
newTemp.child("QuantityCount").setValue(1);
newTemp.child("CountFood1").setValue(1);
newTemp.child("Food1").setValue(foodname);
newTemp.child("FoodPrice1").setValue(foodprice);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
viewHolder.mFoodAddLayout.setVisibility(View.INVISIBLE);
viewHolder.mIncrLayout.setVisibility(View.VISIBLE);
}
});
According to my understanding I have did wrong math while retrieving the data and adding the data back.
addValueEventListener() will always listening to database reference value changes.if you want to stop listening you have to use removeEventListener(valueListener),
But addListenerForSingleValueEvent() executes onDataChange method immediately and after executing that method once, it stops listening to value changes.
You need to use the .addListenerForSingleValueEvent() instead of .addValueEventListener(). The difference is, the second one keep updating every time a value is changed in the database, which keep happening as you update your value inside the function. But, the first method that I am suggesting, just read the values once, which is what you need here.