Thanks for reading this post. I am currently implementing phone OTP for my app in Kotlin in fragment. Since there is no resource available for Fragment and mostly for Activity, therefore, I am applying Activity OTP into my fragment, and as expected, it is crashed once I am inputting a mobile number there and enter login button. It is intended to go to OTP activity once the login button is pressed and mobile number is inserted.
Can you find why it is crashed once from my code below? Thank you so much.
package com.example.myApp
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.Toast
import com.example.myApp.databinding.FragmentLogInPhoneBinding
import com.google.firebase.FirebaseException
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.PhoneAuthCredential
import com.google.firebase.auth.PhoneAuthOptions
import com.google.firebase.auth.PhoneAuthProvider
import kotlinx.android.synthetic.main.fragment_log_in_phone.*
import java.util.concurrent.TimeUnit
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
class LogInPhone : Fragment() {
private lateinit var binding: FragmentLogInPhoneBinding
lateinit var auth: FirebaseAuth
lateinit var storedVerificationId:String
lateinit var resendToken: PhoneAuthProvider.ForceResendingToken
private lateinit var callbacks: PhoneAuthProvider.OnVerificationStateChangedCallbacks
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentLogInPhoneBinding.inflate(layoutInflater, container, false)
binding.loginButtonPhone.setOnClickListener {
login()
}
callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
startActivity(Intent(getActivity()?.applicationContext, MainScreen::class.java))
getActivity()?.finish()
}
override fun onVerificationFailed(e: FirebaseException) {
Toast.makeText(getActivity()?.applicationContext, "Failed", Toast.LENGTH_LONG).show()
}
override fun onCodeSent(
verificationId: String,
token: PhoneAuthProvider.ForceResendingToken
) {
Log.d("TAG","onCodeSent:$verificationId")
storedVerificationId = verificationId
resendToken = token
var intent = Intent(getActivity()?.applicationContext,OTPVerificationPhone::class.java)
intent.putExtra("storedVerificationId",storedVerificationId)
startActivity(intent)
}
}
return binding.root
}
private fun login() {
var number=binding.loginPhoneFragment.text
if(!number.isNullOrEmpty()){
sendVerificationcode (number)
}else{
login_phone_fragment_layout.setError("Masukkan nomor ponsel anda")
}
}
private fun sendVerificationcode(number: Editable?) {
val options = PhoneAuthOptions.newBuilder(auth)
.setPhoneNumber(number.toString()) // Phone number to verify
.setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(this.requireActivity()) // Activity (for callback binding)
.setCallbacks(callbacks) // OnVerificationStateChangedCallbacks
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
companion object {
fun newInstance(param1: String, param2: String) =
LogInPhone().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
By the way this is the original Activity source code: https://blog.codestormx.in/#/blog/Surya VMDS#OAZIadP0VivRQTzAuwrb
Here is the crash log:
2022-02-15 15:13:40.592 7134-7134/com.example.myApp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myApp, PID: 7134
kotlin.UninitializedPropertyAccessException: lateinit property auth has not been initialized
at com.example.myApp.LogInPhone.getAuth(LogInPhone.kt:29)
at com.example.myApp.LogInPhone.sendVerificationcode(LogInPhone.kt:107)
at com.example.myApp.LogInPhone.login(LogInPhone.kt:101)
at com.example.myApp.LogInPhone.onCreateView$lambda-3(LogInPhone.kt:63)
at com.example.myApp.LogInPhone.$r8$lambda$8agyy8FyIIE4Tmrzi_lrnbT4nrs(Unknown Source:0)
at com.example.myApp.LogInPhone$$ExternalSyntheticLambda0.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:7792)
at android.widget.TextView.performClick(TextView.java:16045)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1131)
at android.view.View.performClickInternal(View.java:7769)
at android.view.View.access$3800(View.java:910)
at android.view.View$PerformClick.run(View.java:30184)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8582)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:563)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1133)
2022-02-15 15:13:40.626 7134-7134/com.example.myApp I/Process: Sending signal. PID: 7134 SIG: 9
CodePudding user response:
lateinit var auth: FirebaseAuth
the auth variable is not initialized, when you call the sendVerificationcode() method,
PhoneAuthOptions.newBuilder(auth)
the auth is null, hence the UninitializedPropertyAccessException
you can fix this by initializing auth variable onCreate or onCreateView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
auth = FirebaseAuth.getInstance(); // initialized
}