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.
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 was wondering if there was a way to edit the name and email via code in Android Studio, to change it in Cloud Firestore. I made a program where it only changes the name in real-time and when logged off, and logged in again it changes back to the previous one which is in Cloud Firestore.
vardas is an EditText field in the app design.
My code:
public void updateProfile(final View view) {
view.setEnabled(false);
vardas1 = vardas.getText().toString();
FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
UserProfileChangeRequest request = new UserProfileChangeRequest.Builder()
.setDisplayName(vardas1)
.build();
firebaseUser.updateProfile(request)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
view.setEnabled(true);
Toast.makeText(Profile.this, "Sėkmingai atnaujintas profilis", Toast.LENGTH_SHORT).show();
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
view.setEnabled(true);
Log.e(TAG, "onFailure: ", e.getCause());
}
});
}
I was wondering if there was a way to edit the name and email via code in Android Studio, to change it in Cloud Firestore.
Yes, there is. According to the official documentation regarding how to update a document in Cloud Firestore:
To update some fields of a document without overwriting the entire document, use the update() method.
Assuming you want to update the name and email of the authenticated user that exists at the following reference:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference usersRef = rootRef.collection("users");
DocumentReference uidRef = usersRef.document(uid);
Try the following lines of code:
uidRef.update(
"name", "John",
"email", "john#email.com"
).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "DocumentSnapshot successfully updated!");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "Error updating document", e);
}
});
The result of using this is code, is the update of the name property with "John".
What you are doing in your code is nothing else than updating the name in the FirebaseUser object. That operation is not related in any way with Firestore. So updating the FirebaseUser it doesn't mean that the user will be also updated in the Firestore database. There are two different separate operations that are not related.
I'm creating an app with where I want already signed up users to be redirected to their profile if their phone number is registered in the app, but if he is a new user then he will be redirected to the welcome page.
The problem is, I'm able to get the verification code for the phone number, but it is always redirecting to the welcome page irrespective of whether it is an existing user or a new user.
By far I've implemented Firebase phone authentication, and
private void verifyCode(String code) {
PhoneAuthCredential phoneAuthCredential = PhoneAuthProvider.getCredential(verificationId, code);
signInWithCredentials(phoneAuthCredential);
}
private void signInWithCredentials(PhoneAuthCredential phoneAuthCredential) {
mAuth.signInWithCredential(phoneAuthCredential).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
final String num = getIntent().getStringExtra("phoneNumber");
final Query query = FirebaseDatabase.getInstance().getReference("users").orderByChild("birthday").equalTo(num);
if (task.isSuccessful()) {
if (num.equals(query.toString())) {
Log.i("Method", "Inside if block");
Log.i("value", num + query.toString());
Intent intent = new Intent(VerifyPhoneActivity.this, WelcomeActivity.class);
startActivity(intent);
} else {
Log.i("Method", "Inside if block2");
Log.i("value", num + query.toString());
Intent intent = new Intent(VerifyPhoneActivity.this, ProfileActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
} else {
Toast.makeText(VerifyPhoneActivity.this, task.getException().getMessage(), Toast.LENGTH_LONG).show();
}
}
});
}
I'm taking only the phone number of the user to log in/sign up, and there's no separate button for login and sign up. It should work in such a way that, once the OTP sent by the Firebase auth has been verified and if the phone number is already present in the database, it should directly fo the user's profile page instead of the welcome screen, however, if the phone number is new it should go to the welcome page instead of the user profile page.
The challenge I'm facing is I'm not able to check if the number entered is already present in the database in the user table(I've created a separate user table to store the details of the user when he signs up for the first time).
from what I understood you're able to register users but you're not able to redirect unregistered users to the login/signup screen, if that's the case then you can try to use
FirebaseAuth.getInstance().currentUser
in the on create view method in your welcome/home page it should be something like this
override fun onCreate(savedInstanceState: Bundle?) {
if (FirebaseAuth.getInstance().currentUser == null) {
startActivity(Intent(applicationContext, RegistrationActivity::class.java))
finish()
return
}
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// do your other stuff
}
this code is written in kotlin it shouldn't be that different in java. hope it helps.
UPDATE------
you have a few mistakes with your code, try this
private void verifyCode(String code) {
PhoneAuthCredential phoneAuthCredential = PhoneAuthProvider.getCredential(verificationId, code);
FirebaseAuth.getInstance().signInWithCredential(phoneAuthCredential).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
final String num = getIntent().getStringExtra("phoneNumber");
FirebaseDatabase.getInstance().getReference("users").orderByChild("phoneNumber").equalTo(num).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
Intent intent = new Intent(VerifyPhoneActivity.this, ProfileActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
} else {
FirebaseDatabase.getInstance().getReference("users").push().child("phoneNumber").setValue(num).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Intent intent = new Intent(VerifyPhoneActivity.this, WelcomeActivity.class);
startActivity(intent);
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
} else {
Toast.makeText(VerifyPhoneActivity.this, task.getException().getMessage(), Toast.LENGTH_LONG).show();
}
}
});
}
first of all, you have to log in the user with the phone detail then you check if you have any user registered with that phone number if you do then that means that this user has already entered the app but if you didn't have any information of user with that phone number then you create his information and direct him to the welcome screen after creating his information, so if this user comes back again you will check if we have a record of user with that phone number (which we do) so this time he will be directed to the profile screen
I am trying to detect and connect two Android mobiles using Wifi P2P method and I have been successful in it. But, I want a different name to be shown on the other device when it discovers mine.
Since, I am using Samsung J7 Prime 2(Android 9), changing Device name or Bluetooth name changes the Wifi P2p name, but the code for that didn't work. I tried the same code on Android 6.0.1 i.e. API 23 and it worked fine.
swtWifi.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
changeDevName("Tony Stark");
}
});
public void changeDevName(String devNewName) {
try {
Method method = manager.getClass().getMethod("setDeviceName", WifiP2pManager.Channel.class, String.class, WifiP2pManager.ActionListener.class);
method.invoke(manager, channel, devNewName, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Toast.makeText(MainActivity.this, "Name successfully changed", Toast.LENGTH_LONG).show();
}
#Override
public void onFailure(int reason) {
Toast.makeText(MainActivity.this, "Request failed: " + reason, Toast.LENGTH_SHORT).show();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
I am making a firebase notes app for android as a project (I'm a beginner and never done anything like this). My problem at the moment is that every note made, no matter what user made it, is available for every user to see. I want to make it that every user can only read/write their own notes but all the rules I found and tried so far made it that no notes are sent to the database at all or are not shown. I tried playing around with the code itself as well, but everything I did made the app crash but I'm open to suggestions.
The problem (logged in as user 2) :
The database with two users and the two notes:
I've tried solutions from other similar posts like this:
"rules": {
"tasks": {
"$userId": {
".read": "auth.uid == $userId",
".write": "auth.uid == $userId",
}
}
}
}
But none worked properly so far.
User creation:
fAuth.createUserWithEmailAndPassword(email,password).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
fUserDatabase.child(fAuth.getCurrentUser().getUid()).child("basic").child("name")
.setValue(name).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
progressDialog.dismiss();
Intent mainIntent = new Intent(RegisterActivity.this, MainActivity.class);
startActivity(mainIntent);
finish();
Toast.makeText(RegisterActivity.this, "User Created", Toast.LENGTH_SHORT);
} else {
progressDialog.dismiss();
Toast.makeText(RegisterActivity.this, "Error: " + task.getException().getMessage(), Toast.LENGTH_SHORT);
}
}
});
} else {
progressDialog.dismiss();
Toast.makeText(RegisterActivity.this, "Error: " + task.getException().getMessage(), Toast.LENGTH_SHORT);
}
}
});
Note Creation:
(Not on the same page)
editText = findViewById(R.id.etx);
etd = findViewById(R.id.etdx);
button = findViewById(R.id.btnx);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("posts").push();
Map<String, Object> map = new HashMap<>();
map.put("id", databaseReference.getKey());
map.put("title", editText.getText().toString());
map.put("desc", etd.getText().toString());
databaseReference.setValue(map);
Intent back = new Intent(NewNoteActivity.this, MainActivity.class);
startActivity(back);
}
});
I would like to make it so that every user can only see, edit and delete notes that they made themselves.
I found a solution that might be useful to anyone else who's having troubles with this kind of thing.
I changed the path in the note creation to this:
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("Users").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("posts").push();
Then changed the part of the code that shows the notes accordingly.
This is how it was:
Query query = FirebaseDatabase.getInstance()
.getReference()
.child("posts");
This is how it is now:
Query query = FirebaseDatabase.getInstance()
.getReference()
.child("Users").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("posts");
You cannot keep data as relational database. because firebase database is flat heierarchy. when you design the database use always
/users/user-id/posts
+ item1
+ item2
this is the way you must implement. thanks.