I'm creating an app using Kotlin on Android Studio.
In the app, users will be allowed to add an image, username, and a phone number
to proceed to other activities. The mentioned info should be saved in the app Cloud Firestore (Firebase).
However, while coding the functions for firestore, data is not saved to the database
Can anyone help please?
When I built my app, this is what it showed:
Open the picture
This is my first post on stackoverflow, so let me know if you want to know any addtional infos.
I would appreciate any help from you, guys.
This is my code:
setupBtn.setOnClickListener {
val username: String = setupName.text.toString()
val phoneNumber: String = setupPhoneNumber.text.toString()
if (!TextUtils.isEmpty(username) &&
!TextUtils.isEmpty(phoneNumber)) { //if fields are not empty, proceed. Else,
tell user to fill both fields
setupProgressBar.visibility = View.VISIBLE
val userID = mAuth.currentUser!!.uid // saves user ID
val imagePATH: StorageReference =
storageRef.child("profile_images").child(userID + ".jpg") //store the image
as the user ID
imagePATH.putFile(mainImageURI).addOnCompleteListener {
task ->
if (task.isSuccessful) {
//get the downloadURI of the image and store it
val downloadURI =
task.result.metadata!!.reference!!.downloadUrl.toString()
//A collection stores in the database that has a
1)name .. 2)phone number .. 3)image
val data = HashMap<String, Any>()
data.put("name", username)
data.put("phone number", phoneNumber)
data.put("image", downloadURI)
val docRef =
mFirestore.collection("Users").document(userID).set(data)
docRef.addOnCompleteListener { task ->
if (task.isSuccessful) {
Toast.makeText(this, "User Setting are
updated", Toast.LENGTH_LONG).show()
val intent = Intent(this,
PhotoBlog::class.java)
startActivity(intent)
finish()
} else {
val errorMessage: String? =
task.exception!!.message
Toast.makeText(this, "Database Error:
$errorMessage", Toast.LENGTH_LONG).show()
}
}
} else {
val errorMessage: String? =
task.exception!!.message
Toast.makeText(this, "Image Error:
$errorMessage", Toast.LENGTH_LONG).show()
}
setupProgressBar.visibility = View.INVISIBLE
}
} else {
Toast.makeText(this, "Please, fill both fields",
Toast.LENGTH_LONG).show()
}
}
}
I also imported the needed libraries, and defined a firestore variable
private lateinit var mFirestore: FirebaseFirestore
mFirestore = FirebaseFirestore.getInstance()
Related
How do I retrieve all the fields of the current user logged?
I've watched many tutorials and questions, and some of them talk about the whole collection, others about similar topics, but found no info about this.
Thank you
UPDATE
Current Code:
fun getUserName_FireBase(){
if(userID==null){
println("The userID is null")
userID= getUserID()
println("The userId has been assigned and now is: " + userID.toString())
}
println("1")
val db = FirebaseFirestore.getInstance()
println("1a")
val usersRef = db.collection("users")
println("1b")
usersRef.document(userID.toString()).get().addOnCompleteListener { task ->
println("2")
if (task.isSuccessful) {
println("3")
val document = task.result
if(document!!.exists()){
println("4")
userName = document!!.getString("user").toString()
println("user is " + userName.toString())
}else {
println("5")
Log.d("Error", "This document does not exist")
}
}else {
println("6")
task.exception?.message?.let {
Log.d(TAG, it)
}
}
println("7")
}
println("8")
}
Console error
The error is given because later I need to acces to userName var that is supposed to be filled in that function
To be able to get user data, you have to create a reference that points to that document, perform a get() call and attach a listener, as seen in the following lines of code:
val db = FirebaseFirestore.getInstance()
val usersRef = db.collection("users")
usersRef.document("gA4z1AhkQpQ6J47sIMmCGIZRKDK2").get().addOnCompleteListener { task ->
if (task.isSuccessful) {
val document = task.result
if (document.exists()) {
val email = document.getString("email")
val pass = document.getString("pass")
val user = document.getString("user")
Log.d(TAG,"$email/$pass/$user")
} else {
Log.d(TAG, "The document doesn't exist.")
}
} else {
task.exception?.message?.let {
Log.d(TAG, it)
}
}
}
The result in the logcat will be:
barrooroor#gmail.com/paport/do3fe4232ef2
If "gA4z1AhkQpQ6J47sIMmCGIZRKDK2" is the ID of the user that comes from the authentication process, then instead of the hard coded ID, you can simply use:
val auth = FirebaseAuth.getInstance()
val uid = auth.currentUser?.uid
usersRef.document(uid).get().addOnCompleteListener {/* ... /*}
// 👆
Besides that, something more important, never store sensitive data as passwords in plain text. Malicious users might take advantage of that. Always use Firebase Authentication for that and secure the database using Firestore Security Rules.
As creating a form that stored the candidate's basic info along with a pic, as I click on upload btn data which is entered in edit text does not match data stored in firebase.
upload activity
binding.btnUpload.setOnClickListener {
showProgressBar()
val name= binding.etName.toString()
val fathers_name =binding.etFatherName.toString()
val gender=binding.etGender.toString()
val dob=binding.etDob.toString()
val time_place = binding.etTimePlace.toString()
val qualification = binding.etQualification.toString()
val job = binding.etJob.toString()
val Height = binding.etHeight.toString()
val fathers_qualification = binding.etFatherQualification.toString()
val requirement = binding.etRequirement.toString()
val address = binding.etAddress.toString()
val contact=binding.etContact.toString()
// val imageUrl = imageUri.toString()
val candidate= Candidates(name,fathers_name,gender,dob,time_place,
qualification,job,Height,fathers_qualification,requirement,address, contact)
database.child( System.currentTimeMillis().toString()).setValue(candidate).addOnCompleteListener{
if (it.isSuccessful){
uploadProfilePic()
}else{
hideProgressBar()
Toast.makeText(this, "Failed to upload profile", Toast.LENGTH_SHORT).show()
}
Toast.makeText(this, "Successfully saved", Toast.LENGTH_SHORT).show()
}.addOnFailureListener {
Toast.makeText(this, "Failed", Toast.LENGTH_SHORT).show()
}
}
}
private fun uploadProfilePic() {
storageRef= FirebaseStorage.getInstance().getReference("candidates")
storageRef.putFile(imageUri).addOnSuccessListener {
Toast.makeText(this, "profile picture uploaded", Toast.LENGTH_SHORT).show()
hideProgressBar()
}.addOnFailureListener {
hideProgressBar()
Toast.makeText(this, "failed to upload the profile pic", Toast.LENGTH_SHORT).show()
}
}
As entered basic details, but it showing some wired data into database.
When you call this:
val name= binding.etName.toString()
The name variable becomes the string representation of the EditText object itself, not of the text value that the user entered.
To get the actual value, use
val name = binding.etName.getText().toString()
I am trying to write some basic information about users to a Firebase realtime database, but when running setValue() nothing happens in the console and after many hours of trying I still can't figure out the problem.
This is the code in the fragment that calls the registerUser function:
registerButton.setOnClickListener {
firstNameLayout.error = null
lastNameLayout.error = null
emailFieldLayout.error = null
passwordFieldLayout.error = null
var fieldCheck = true
if(TextUtils.isEmpty(firstNameField.text)) {
firstNameLayout.error = "Please Enter First Name";
fieldCheck = false
}
if (TextUtils.isEmpty(lastNameField.text)) {
lastNameLayout.error = "Please Enter Last Name"
fieldCheck = false
}
if(TextUtils.isEmpty(emailField.text)) {
emailFieldLayout.error = "Please Enter Email Address";
fieldCheck = false
// Todo: Make sure format is correct
}
if(TextUtils.isEmpty(passwordField.text)){
passwordFieldLayout.error = "Please Choose a Password"
fieldCheck = false
// Todo: Stricter password requirements
}
if(!fieldCheck) {
return#setOnClickListener
}
registerButton.startAnimation()
val fName = firstNameField.text.toString().trim()
val lName = lastNameField.text.toString().trim()
val email = emailField.text.toString().trim()
val password = passwordField.text.toString().trim()
try {
registerButton.doneLoadingAnimation(2, bitmap)
(activity as LoginRegister).registerUser(email, password, fName, lName)
} catch (e: Exception) {
Toast.makeText(activity, e.message, Toast.LENGTH_SHORT).show()
registerButton.revertAnimation()
}
}
This is the registerUser function body from the parent activity of the fragment:
fun registerUser(email: String, password: String, fName: String, lName: String) {
//Registrerer med Firebase Authentication
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "createUserWithEmail:success")
val user : FirebaseUser = task.result!!.user!!
val uid: String = user.uid
val dbUser = User(fName, lName, email)
writeNewUser(uid, dbUser)
val intent = Intent(this#LoginRegister, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
intent.putExtra("user_email", email)
intent.putExtra("user_first_name", fName)
intent.putExtra("user_last_name", lName)
startActivity(intent)
finish()
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "createUserWithEmail:failure", task.exception)
Toast.makeText(baseContext, "Authentication failed.", Toast.LENGTH_SHORT).show()
}
}
}
This is the writeNewUser function body
fun writeNewUser(userId: String, user: User) {
database = FirebaseDatabase.getInstance().getReference("Users").child(userId)
database.child("users").child(userId).setValue(user)
}
The User object is instantiated from this kotlin class:
data class User(val fName: String? = null, val lName: String? = null, val email: String? = null) {
val firstName = fName?.capitalize(Locale.ROOT)
val lastName = lName?.capitalize(Locale.ROOT)
val emailAddress = email
}
Firebase:
Firebase nodes
Anyone know the reason behind this?
put the URL of database in the getInstance() was the solution for me, now it works perfect
example:
private val database = FirebaseDatabase.getInstance("https://conect-c91b3-default-rtdb.firebaseio.com/").getReference()
// to test if is working
database.child("users").setValue("test")
I solved it, I was using another database location than the default, and I didn't catch the fact that I needed to pass the database URL in the getInstance() method. Passing the correct database url fixed the issue
fun writeNewUser(userId: String, user: User) {
database = FirebaseDatabase.getInstance().getReference("Users").child(userId)
database.child("users").child(userId).setValue(user)
}
I guess you duplicate a couple of child nodes in above snippet as it implies a group of users has a single user, and this particular user has a group of users, doesn't make sense, so you can remove these duplicates:
fun writeNewUser(userId: String, user: User) {
database = FirebaseDatabase.getInstance().getReference("Users").child(userId)
database.setValue(user)
}
UPDATE:
The firebase nodes are case-sensitive, so change "Users" to lowercase "users"
fun writeNewUser(userId: String, user: User) {
database = FirebaseDatabase.getInstance().getReference("users").child(userId)
database.setValue(user)
}
I'm building an app and I have Firestore server, when specific button pressed I wanted to get data from firebase and save it to the Shared Preference but it's no seem to work.
db.collection("Groups1").document("${codeEntered}").get().addOnSuccessListener {doc ->
if(doc.exists()){
val groups = sharedPreferences.getStringSet("groupCodes", HashSet<String>())
if(groups?.contains(codeEntered)!!){
Toast.makeText(getApplicationContext(), "You're Already in ${codeEntered}.", Toast.LENGTH_LONG).show()
}else {
Toast.makeText(getApplicationContext(), "You Enter ${codeEntered} Group!", Toast.LENGTH_LONG).show()
groups?.plusAssign(codeEntered)
editSharedPreferences.putStringSet("groupCodes", groups)
val data = doc.data.hashCode()
//Add Set The Group In FireStore
db.collection("Groups1").document(codeEntered).get().addOnSuccessListener {doc ->
var data = doc.getData() as MutableMap<String, Any>
data["${sharedPreferences.getInt("mainId", 0)}"] = 0
db.collection("Groups1").document(codeEntered).set(data)
editSharedPreferences.apply()
}
getData(object : MyCallback {
override fun onCallback(value: HashMap<String, Int>) {
listView.adapter = adapterListView(MainActivity.appContext, value, sizeOfListMain, sharedPreferences.getInt("mainColor", 0)) }
})
var codeGroup = sharedPreferences.getStringSet("groupCodes", HashSet<String>()) as HashSet<String>
}
}else{
Toast.makeText(getApplicationContext(), "${codeEntered} is Not Exists.", Toast.LENGTH_LONG).show()
}
}
This question already has answers here:
How to return a list from Firestore database as a result of a function in Kotlin?
(3 answers)
Closed 3 years ago.
I wonder why the onCompleteListener is not called but the data are saved to the FireBaseDatabase successfully.
I just want to say: if the data are saved to FireBaseDatabase, set isSuccedded to true, but this does not happen. isSucceeded is always false.
val isSaved = SaveUserToDatabase(username)
if (isSaved) {
Toast.makeText(this, "Success", Toast.LENGTH_SHORT).show()
val intent = Intent(this, LatestTransactions::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK.or(Intent.FLAG_ACTIVITY_CLEAR_TASK)
intent.putExtra(CURRENT_USER, mAuth.currentUser.toString())
startActivity(intent)
} else {
register_tv_error.text = "Couldn't save user"
}
and the function:
private fun SaveUserToDatabase(username: String): Boolean {
val uid = mAuth.uid
var isSucceeded = false
val user = User(uid!!, username)
myRef = database.getReference("/users/$uid")
myRef.setValue(user).addOnCompleteListener{
if(it.isSuccessful){
isSucceeded = true
}
}
return isSucceeded
}
What is the Problem?
Please avoid returning data from method that runs asynchronously code.
Your logic can be like this.
private fun SaveUserToDatabase(username: String){
val uid = mAuth.uid
val user = User(uid!!, username)
myRef = database.getReference("/users/$uid")
myRef.setValue(user).addOnCompleteListener{
if(it.isSuccessful){
updateView(it.isSuccessful);
}
}
}
private fun updateView(isSuccess: Boolean){
if (isSuccess) {
Toast.makeText(this, "Success", Toast.LENGTH_SHORT).show()
val intent = Intent(this, LatestTransactions::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK.or(Intent.FLAG_ACTIVITY_CLEAR_TASK)
intent.putExtra(CURRENT_USER, mAuth.currentUser.toString())
startActivity(intent)
} else {
register_tv_error.text = "Couldn't save user"
}
For more info read asynchronous-vs-synchronous in this question