I want to start new activity when a value ("Status") change in my Database Firebase.
But i have problem because onActivityCreated is launched three times (because my onDataChange of my Listener is called several times). How can i fix this ? Thank you in advance.
//LISTEN IF THE GAME START ::
mStart = FirebaseDatabase.getInstance().getReference().child("Rooms").child(roomId).child("Proprieties").child("Status");
mStart.addValueEventListener(new ValueEventListener(){
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue().equals("GAME")){
Intent intent = new Intent(WaitGameActivity.this,GameActivity.class);
startActivity(intent);
finish();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) { }
});
And Log :
V/FA: onActivityCreated
V/FA: onActivityCreated
V/FA: onActivityCreated
You could remove the value listener once you receive an event like below:
mStart.addValueEventListener(new ValueEventListener(){
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
mStart.removeValueEventListener(this); //remove once you get the event
if (dataSnapshot.getValue().equals("GAME")){
Intent intent = new Intent(WaitGameActivity.this,GameActivity.class);
startActivity(intent);
finish();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) { }
});
onDataChange is called multiple times in case you have not removed the listener properly and are creating a new instance of your listener in your activity every time you open it.
Call this once you recieved data:
mStart.removeValueEventListener(this)
Related
In my application, I have four users--they have same user login and separate registration. If a doctor log in he will go to the the company activity. How will I make sure that the email is a patient or an doctor or company or pharmacy?
That image shows my firebase structure
Here is my code I try:
if (user != null) {
ref = FirebaseDatabase.getInstance().getReference().child("").child(user.getUid()).child("type");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String value = dataSnapshot.getValue(String.class);
if ("doctor".equals(value)) {
startActivity(new Intent(SplashActivity.this, doctor_profile.class));
finish();
} else if ("patient".equals(value)) {
startActivity(new Intent(SplashActivity.this, PatientActivity.class));
finish();
} else if ("pharmacy".equals(value)) {
startActivity(new Intent(SplashActivity.this, PharmacyActivity.class));
finish();
} else {
startActivity(new Intent(SplashActivity.this, CompanyActivity.class));
finish();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
So starting from your implementation, you need to check each child that represents a user type to find the id of your user and start the correct Activity. There are many ways to solve your problem.
A simple way would be to define a Map<String, Class> in which each key is the name of your user type on Firebase ("Company", "Doctors"...) and each value associated is the Class object of the related Activity that you want to start. An example of adding a key-value to this map would be: mMap.put("Company", CompanyActivity.class);.
Then you can add a ValueEventListener() for each user type and use the map to avoid repeating code:
if (user != null) {
DatabaseReference ref = FirebaseDatabase.getInstance().getReference(); // find the right path in which your user types live
for (Map.Entry<String, Class> entry : mMap) {
ref.child(entry.getKey()).child(user.getUid())
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange (DataSnapshot dataSnapshot){
if (dataSnapshot.getValue() != null) { // if value isn't null, then user is of this type and it's possible to start the correct activity
Intent i = new Intent(SplashActivity.this, entry.getValue());
startActivity(i);
finish();
}
}
#Override
public void onCancelled (DatabaseError databaseError){
}
});
}
}
This implementation keeps the single login.
If the user has signed in at least one time, you could think about storing its type in the preferences and then check directly the right child in RealTime Database (this is possible only if he doesn't have to log in again, in which case, obviously, you don't know which e-mail the user is going to use).
I built an app on Android Studio that works perfectly fine, but there´s something that I can´t understand since I´ve tested the app on 6 different android devices, and it works fine with 4 of them, in one of them the app crashes after the registry activity, and in the other one everything works fine until a button is pressed, but it is strange because neither of this errors happens on the other 4 devices.
I can't see any patterns, my only clue is that both of them are related to a process of writing of Shared Preferences I leave the code to you.
I hope you can figure out what I can't see.
mDataBase.child("Users").child("A").addListenerForSingleValueEvent(new ValueEventListener() { // Lectura
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String numcliente = Objects.requireNonNull(dataSnapshot.child("Numero Cliente").getValue()).toString(); // Obtiene valor
Toast.makeText(registro1.this, "Su numero de cliente es: " + numcliente, Toast.LENGTH_SHORT).show();
// Note: This Toast works fine //
SharedPreferences.Editor editor = cliente.edit();
editor.putString("km", km);
editor.putString("numcliente", numcliente);
editor.putString("cel", number);
editor.putString("dir", dir);
editor.putString("ent1", ent1);
editor.putString("ent2", ent2);
editor.putString("name", name);
editor.apply();
final Map <String, Object> map = new HashMap<>();
map.put("Nombre", name);
map.put("Correo Electronico", email);
map.put("Celular", number);
map.put("Contraseña", password);
map.put("Kilometro", km);
map.put("Direccion", dir);
map.put("Entrecalle 1", ent1);
map.put("Entrecalle 2", ent2);
map.put("Referencia", desc);
// map.put("Numero Cliente", numcliente);
//final String id = Objects.requireNonNull(mAuth.getCurrentUser()).getUid();
mDataBase.child("Users").child(numcliente).setValue(map).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task2) {
if(task2.isSuccessful()){
mDataBase.child("Users").child("A").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String numcliente = Objects.requireNonNull(dataSnapshot.child("Numero Cliente").getValue()).toString();
int numcliente1 = Integer.parseInt(numcliente);
final int numcliente2 = numcliente1 + 1;
//final String numclientefinal = Integer.toString(numcliente2);
Map<String, Object> numclientenew = new HashMap<>();
numclientenew.put("Numero Cliente", numcliente2);
mDataBase.child("Users").child("A").setValue(numclientenew).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
//Toast.makeText(registro1.this, "Proximo usuario es " + numcliente2, Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
startActivity(new Intent(registro1.this, menu.class));
finish();
}else{
Toast.makeText(registro1.this, "No se pudieron crear los datos", Toast.LENGTH_SHORT).show();
}
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
In which device application is crashing, connect is to android studios run an application inside it then simultaneously open logcat in android studios when application gets crashed see in logcat it will show you the reason for crashing the application.
Ok, I connected the problematic device to my computer, and I did what Vaibhav Kadam told me in his answer. The Logcat gave me a "java.lang.OutOfMemory" trouble, so I came to my beatiful Stack Overflow and I founded this:
How to solve java.lang.OutOfMemoryError trouble in Android.
So, I used this simple line android:largeHeap="true" in the AndoridManifest.xml to avoid this memory problem. And it worked on all the problematic devices. It was simpler than i thought.
I am working on my App, and till now the App runs fine despite some small errors. The user can sign in, login and change his profile information. In the last steps, I added a function to delete userinformation. The delete function works so the userinformation gets deleted from FirebaseAuth and the FirebaseRealtimeDatabase but the app crashes.
Before I already had problems with passing null values, maybe thats related to the problem.
Update: I changed the code and tried to implement the suggestions but its still crashing...
Logcat:
09-18 16:28:20.474 23342-23342/com.example.login E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.login, PID: 23342
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.example.login.UserProfil.getVorname()' on a null object reference
at com.example.login.ProfileActivity$1.onDataChange(ProfileActivity.java:59)
at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database##19.0.0:75)
at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database##19.0.0:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database##19.0.0:55)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:234)
at android.app.ActivityThread.main(ActivityThread.java:5526)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Some part of my ProfileActivity
firebaseAuth=FirebaseAuth.getInstance();
firebaseDatabase= FirebaseDatabase.getInstance();
if (firebaseAuth.getCurrentUser() != null) {
firebaseDatabase= FirebaseDatabase.getInstance();
final DatabaseReference databaseReference = firebaseDatabase.getReference("Users").child(firebaseAuth.getUid());
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) ;
{
UserProfil userProfil = dataSnapshot.getValue(UserProfil.class);
profilVorname.setText(userProfil.getVorname());
profilNachname.setText(userProfil.getNachname());
profilStrasse.setText(userProfil.getStrasse());
profilHNr.setText(userProfil.getHnr());
profilPlz.setText(userProfil.getPlz());
profilStadt.setText(userProfil.getStadt());
profilLand.setText(userProfil.getLand());
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(ProfileActivity.this, "Database Error", Toast.LENGTH_SHORT).show();
}
});
}else{
startActivity(new Intent(ProfileActivity.this,NavActivity.class));
}
Some part of my UpdatProfilActivity
loeschen.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final DatabaseReference databaseReference = firebaseDatabase.getReference("Users").child(firebaseAuth.getUid());
databaseReference.removeValue();
FirebaseUser user= FirebaseAuth.getInstance().getCurrentUser();
user.delete().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
// firebaseAuth.signOut();
// startActivity(new Intent(UpdateProfilActivity.this, MainActivity.class));
//finish();
}
}
});
}
});
This is most probably due to that the 'dataSnapshot' object is null when onDataChange() is triggered upon deletion; you can return if it is null
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (!dataSnapshot.exists())
return;
UserProfil userProfil = dataSnapshot.getValue(UserProfil.class);
profilVorname.setText(userProfil.getVorname());
profilNachname.setText(userProfil.getNachname());
profilStrasse.setText(userProfil.getStrasse());
profilHNr.setText(userProfil.getHnr());
profilPlz.setText(userProfil.getPlz());
profilStadt.setText(userProfil.getStadt());
profilLand.setText(userProfil.getLand());
}
When addValueEventListener is used, then it listens on every event what happened with current reference. And when you delete it then dataSnapshot in listener comes null and on getVorname() exception is thrown.
I"m stuck in one problem. My firebase structure is given in image where subject is the child value i get using intent extra on click from button
consider I have two buttons Button A and Button B
when I press Button A then it will sent subject as string value of "Bhaktapur" and now I have details of Bhaktapur in Recycleview but when I clcik Button B if it pass an string value "xyz" then I have no any value with data "xyz" then It should return to Mainactivity with Toast message " Not Found"
But The first one works fine and recycleview is updated with information but on second case I have progress Dialog keeps loading untill I cancel it.
Here is my code
dbreference =
FirebaseDatabase.getInstance().getReference("books").child(subject);
dbreference.addListenerForSingleValueEvent(new
ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot data : snapshot.getChildren()) {
if (!data.exists()) {
progressDialog.dismiss();
Toast.makeText(SubjectBooks.this, "No books
found!", Toast.LENGTH_SHORT).show();
Intent in = new Intent(SubjectBooks.this,
MainActivity.class);
startActivity(in);
finish();
} else {
final Books b1 = data.getValue(Books.class);
// Log.e("Value is ",dataSnapshot.getKey()+"
"+b1.getBauthor());
//Log.e("Book"," received");
child_count++;
list.add(b1);
staggeredBooksAdapter.notifyDataSetChanged();
progressDialog.dismiss();
}
}
}
Any help is appreciated. Thanks in advance.
I clcik Button B if it pass an string value "xyz" then I have no any
value with data "xyz" then It should return to Mainactivity with Toast
message " Not Found"
Because no data found against xyz, for loop will not be executed neither if-else.As you are dismissing the progress bar inside if-else, it will keep showing indefinitely. So you've to check if DataSnapshot exist before for loop as follows
dbreference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
if (snapshot.exists()) {
// TODO: handle the case where the data exists
for (DataSnapshot data : snapshot.getChildren()) {
final Books b1 = data.getValue(Books.class);
// Log.e("Value is ",dataSnapshot.getKey()+"
"+b1.getBauthor());
//Log.e("Book"," received");
child_count++;
list.add(b1);
staggeredBooksAdapter.notifyDataSetChanged();
progressDialog.dismiss();
}
}
else {
// TODO: handle the case where the data does not yet exist
progressDialog.dismiss();
Toast.makeText(SubjectBooks.this, "No books
found!", Toast.LENGTH_SHORT).show();
Intent in = new Intent(SubjectBooks.this,
MainActivity.class);
startActivity(in);
finish();
}
}
#Override
public void onCancelled(FirebaseError firebaseError) { }
});
I get java.lang.NullPointerException: Can't pass null for argument 'pathString' in child() when my code reaches the valueEventListener although while debugging, it seems to me that the child value is not null.
Here is the image of the code:
This is how the database looks like:
Solved the problem by completely deleting the code and starting again. This time I checked with firebase github and I did it like this(mostly the same thing? i wish i knew what was wrong with my first code):
userReference = FirebaseDatabase.getInstance().getReference().child("users").child(uid);
ValueEventListener userListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
//Get user object
currentUser = dataSnapshot.getValue(User.class);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// [START_EXCLUDE]
Toast.makeText(UserAreaActivity.this, "Failed to load post.",
Toast.LENGTH_SHORT).show();
}
};
userReference.addValueEventListener(userListener);
The only place, in the code shown, where you could get a NPE with that message is in the call:
...child("users").child(uid);
So I'd check that uid variable, work out a way to deal with such scenario (uid == null).
Simply use the following code:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference uidRef = rootRef.child("users").child(uid);
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String country = dataSnapshot.child("country").getValue(String.class);
String city = dataSnapshot.child("city").getValue(String.class);
Log.d(TAG, country + " / " + city);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d(TAG, databaseError.getMessage()); //Don't ignore errors!
}
};
uidRef.addListenerForSingleValueEvent(valueEventListener);
The output in the logcat will be the exact country and city of your user.
Use getValue(String.class) instead of getValue().toString();
You are using unnecessary for loop.You already know what user uid is.Remove for loop then try again.