Issue
This activity registers a user in firebase auth, uploads info in Realtime database and uploads user picture in Storage. This code (I don't know why) gets stuck when it registers the user. If you see, I've added Log statements to break this entire process. The log is like
STARTING PROCESS
BEFORE
INSIDE
No other statement. I think I am using coroutines correctly but I don't know why this program doesn't go further than this ^. Should I use callbacks? Am I using coroutines in a wrong way?A lso any other suggestion will be appreciated.
class SignUpActivity : AppCompatActivity() {
private lateinit var binding: ActivitySignUpBinding
private lateinit var firebaseAuth : FirebaseAuth
private lateinit var firebaseStorage: FirebaseStorage
private lateinit var firebaseDatabase: FirebaseDatabase
val TAG ="SIGNUPATAG"
var selectedPhoto : Uri? = null
var IMAGE_RESPONE_CODE = 1;
var isOk = false;
val imageUrl : String = "."
var userUID = "."
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySignUpBinding.inflate(layoutInflater)
setContentView(binding.root)
firebaseAuth = FirebaseAuth.getInstance()
binding.signupTvSelectPhoto.setOnClickListener {
val intent = Intent();
intent.type = "image/*"
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"Select Pic"),IMAGE_RESPONE_CODE)
}
binding.signupBtnSignUp.setOnClickListener {
val email = binding.signupEtvEmail.text.toString()
if(email.isEmpty() || !Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
binding.signupEtvEmail.error = "Invalid Email Address"
binding.signupEtvEmail.requestFocus()
return@setOnClickListener
}
if(binding.signupEtvName.text.length < 3) {
binding.signupEtvName.error= "Name should at least have 3 characters"
binding.signupEtvName.requestFocus()
return@setOnClickListener
}
val password = binding.signupEtvPassword.text.toString()
if(password.length < 4) {
binding.signupEtvPassword.error = "Password should at least have 4 characters."
binding.signupEtvPassword.requestFocus()
return@setOnClickListener
}
// All Okay
Log.d(TAG,"STARTING PROCESS")
binding.pbSignup.visibility = View.VISIBLE
createAccount(email,password,binding.signupEtvName.text.toString())
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(requestCode == 1) {
if(data != null) {
selectedPhoto = data?.data
binding.signupImgvPhoto.setImageURI(selectedPhoto)
}
else {
val context = this
selectedPhoto = Uri.parse(
ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
+ context.getResources().getResourcePackageName(R.drawable.profilepicnormall) + '/'
+ context.getResources().getResourceTypeName(R.drawable.profilepicnormall) + '/'
+ context.getResources().getResourceEntryName(R.drawable.profilepicnormall) )
}
}
}
private fun createAccount(email : String, password : String,name:String) {
val context = this
selectedPhoto = Uri.parse(
ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
+ context.getResources().getResourcePackageName(R.drawable.profilepicnormall) + '/'
+ context.getResources().getResourceTypeName(R.drawable.profilepicnormall) + '/'
+ context.getResources().getResourceEntryName(R.drawable.profilepicnormall) )
lifecycleScope.async(Dispatchers.Main) {
async {
create(email,password)
}.await()
Log.d(TAG,"The isOk is $isOk")
if(isOk){
async {
Log.d(TAG,"in 1 async")
uploadImage()
}.await()
async {
Log.d(TAG,"in 2 async")
uploadDataToRealtimeDatabase(userUID,email,name,imageUrl)
}.await()
binding.pbSignup.visibility = View.GONE
val intent = Intent(applicationContext,MainActivity::class.java)
startActivity(intent)
finish()
}
binding.pbSignup.visibility = View.GONE
}
}
suspend fun create(email: String,password: String) {
Log.d(TAG,"BEFORE")
firebaseAuth.createUserWithEmailAndPassword(email,password).addOnCompleteListener(parent) {task ->
if(task.isSuccessful) {
Toast.makeText(this@SignUpActivity,"SignUp Successful.",Toast.LENGTH_SHORT).show()
isOk = true;
userUID = firebaseAuth.currentUser!!.uid
Log.d(TAG,"INSIDE")
return@addOnCompleteListener
}
else {
Log.d(TAG,"${task.exception} . ")
Toast.makeText(this@SignUpActivity,"SignUp Not Successful.",Toast.LENGTH_SHORT).show()
}
}
Log.d(TAG,"AFTER")
}
suspend fun uploadDataToRealtimeDatabase(UID:String,userEmail: String,userName : String,url:String) {
Log.d(TAG,"in upload data")
val ref = FirebaseDatabase.getInstance("https://firechat-931d2-default-rtdb.asia-southeast1.firebasedatabase.app/")
.getReference("/users/$UID")
val userinfo = UserInfo(userEmail,UID,userName,url)
ref.setValue(userinfo).addOnSuccessListener {
Log.d(TAG,"UPLOADED USER INFORMATION")
}.addOnFailureListener{
Log.d(TAG,"${it.message} $it")
}
}
suspend fun uploadImage() : String {
Log.d(TAG,"in upload Image")
val profilePicName = "${firebaseAuth.uid}.profileImage"
var url = "."
val storage_reference = FirebaseStorage.getInstance("gs://firechat-931d2.appspot.com").getReference("/ProfileImages/$profilePicName")
storage_reference.putFile(selectedPhoto!!).continueWithTask { task ->
if (!task.isSuccessful) {
Log.d(TAG,"${task.exception}")
}
storage_reference.downloadUrl.addOnSuccessListener {
url = it.toString()
}.addOnFailureListener{
Log.d(TAG,"$it ${it.message}")
}
}
if(url.length < 2) {
Log.d(TAG,"Going with default url.")
url = "https://firebasestorage.googleapis.com/v0/b/firechat-931d2.appspot.com/o/ProfileImages%2FsqE6s03wgXQm7gl03xxQIM3JVQc2.profileImage?alt=media&token=640266a5-6611-4e09-b8ed-72ba8bdfdc1f"
}
Log.d(TAG,"returning the img url $url")
return url
}
}
Solution
I implemented only the signup part in a dummy app after fixing some issues with your code, here are my observations:
No other statement
My logs were as follows:
D/SIGNUPATAG: STARTING PROCESS
D/SIGNUPATAG: INSIDE
D/SIGNUPATAG: The isOk is true
D/SIGNUPATAG: in 1 async
D/SIGNUPATAG: in upload Image
D/SIGNUPATAG: in 2 async
D/SIGNUPATAG: in upload data
I think I am using coroutines correctly but I don't know why this program doesn't go further than this ^. Should I use callbacks? Am I using coroutines in a wrong way?
I don't think you're using coroutines as intended, Firebase
calls are already asynchronous so you don't require to do it this way, you should use Firebase coroutines instead which have built-in support for this case. I am adding the changes that I made below. (Omitting the stuff that doesn't require any change)
build.gradle
//firebase coroutines dependency
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.4.2"
SignUpActivity.kt
class SignUpActivity : AppCompatActivity() {
private lateinit var binding: ActivitySignUpBinding
.
.
override fun onCreate(savedInstanceState: Bundle?) {
.
.
}
private fun createAccount(email : String, password : String,name:String) {
lifecycleScope.launch(Dispatchers.Main) {
val createdUserJob = launch {
try {
Toast.makeText(this@SignUpActivity,"SignUp Successful.",Toast.LENGTH_SHORT).show()
isOk = true;
userUID = firebaseAuth.currentUser!!.uid
Log.d(TAG,"INSIDE")
firebaseAuth.createUserWithEmailAndPassword(email, password).await()
} catch (e: Exception) {
Toast.makeText(this@SignUpActivity,"SignUp Not Successful.",Toast.LENGTH_SHORT).show()
e.printStackTrace()
}
}
createdUserJob.join()
Log.d(TAG,"The isOk is $isOk")
if(isOk){
val uploadImageJob = launch {
Log.d(TAG,"in 1 async")
uploadImage()
}
uploadImageJob.join()
val uploadDataJob = launch {
Log.d(TAG,"in 2 async")
uploadDataToRealtimeDatabase(userUID,email,name,imageUrl)
}
uploadDataJob.join()
binding.pbSignup.visibility = View.GONE
val intent = Intent(applicationContext,MainActivity::class.java)
startActivity(intent)
finish()
}
binding.pbSignup.visibility = View.GONE
}
}
suspend fun uploadDataToRealtimeDatabase(UID:String,userEmail: String,userName : String,url:String) {
Log.d(TAG,"in upload data")
.
.
}
suspend fun uploadImage() : String {
Log.d(TAG,"in upload Image")
.
.
return "dummy"
}
}
Note: I have only tested the signup part, you need to test the image upload and upload data part on your own, I've removed the create(email: String,password: String)
method as well.
Answered By - mehul bisht
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.