Hello I am getting this exception continuously on launch of app :
2019-02-18 16:33:14.735 2080-2080/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: assus.oumayma.com.firebasekotlinapp, PID: 2080
java.lang.RuntimeException: Unable to start activity ComponentInfo{assus.oumayma.com.firebasekotlinapp/assus.oumayma.com.firebasekotlinapp.MainActivity}: java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process assus.oumayma.com.firebasekotlinapp. Make sure to call FirebaseApp.initializeApp(Context) first.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2725)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2786)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1501)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:173)
at android.app.ActivityThread.main(ActivityThread.java:6459)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:938)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:828)
Caused by: java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process assus.oumayma.com.firebasekotlinapp. Make sure to call FirebaseApp.initializeApp(Context) first.
at com.google.firebase.FirebaseApp.getInstance(com.google.firebase:firebase-common##16.0.2:240)
at com.google.firebase.auth.FirebaseAuth.getInstance(Unknown Source)
at assus.oumayma.com.firebasekotlinapp.MainActivity.onCreate(MainActivity.kt:23)
at android.app.Activity.performCreate(Activity.java:6673)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1136)
and this the code:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mAuth = FirebaseAuth.getInstance()
signOut.setOnClickListener {
view: View? -> mAuth.signOut()
startActivity(Intent(this, PhoneAuthenfication::class.java))
Toast.makeText(this, "Logged out Successfully :)", Toast.LENGTH_LONG)
.show()
}
}
override fun onStart() {
super.onStart()
if (mAuth.currentUser == null) {
startActivity(Intent(this, PhoneAuthenfication::class.java))
} else {
Toast.makeText(this, "Already Signed in :)", Toast.LENGTH_LONG).show()
}
}
}
class PhoneAuthenfication : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_phone_authenfication)
mAuth = FirebaseAuth.getInstance()
veriBtn.setOnClickListener { view: View? ->
progress.visibility = View.VISIBLE
verify()
}
authBtn.setOnClickListener { view: View? ->
progress.visibility = View.VISIBLE
authenticate()
}
}
private fun verificationCallbacks() {
mCallbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
progress.visibility = View.INVISIBLE
signIn(credential)
}
override fun onVerificationFailed(p0: FirebaseException?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onCodeSent(verfication: String?, p1: PhoneAuthProvider.ForceResendingToken?) {
super.onCodeSent(verfication, p1)
verificationId = verfication.toString()
progress.visibility = View.INVISIBLE
}
}
}
private fun verify() {
verificationCallbacks()
val phnNo = phnNoTxt.text.toString()
PhoneAuthProvider.getInstance().verifyPhoneNumber(
phnNo,
60,
TimeUnit.SECONDS,
this,
mCallbacks
)
}
private fun signIn(credential: PhoneAuthCredential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener { task: Task<AuthResult> ->
if (task.isSuccessful) {
toast("Logged in Successfully :)")
startActivity(Intent(this, MainActivity::class.java))
}
}
}
private fun authenticate() {
val verifiNo = verifiTxt.text.toString()
val credential: PhoneAuthCredential = PhoneAuthProvider.getCredential(verificationId, verifiNo)
signIn(credential)
}
private fun toast(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_LONG).show()
}
the build.gradle:
implementation 'com.google.firebase:firebase-auth:16.1.0'
implementation 'com.google.firebase:firebase-core:16.0.7'
You are trying to get an instance of Firebase without initialise it. Please add this line of code before you try to get an instance of Firebase:
FirebaseApp.initializeApp(this);
If you are using google service 4.1.0
classpath 'com.google.gms:google-services:4.1.0'
then update the version to
classpath 'com.google.gms:google-services:4.2.0'
Related
I'm Trying to make a viewmodel scoped to my application to control logic related to showing of not showing pin in multi activity app .
I've used AndroidViewModel to pass the application to it and here is the class for AppViewModel
#HiltViewModel
class AppViewModel #Inject constructor(
private val getUserPassCodeUseCase: GetUserPassCodeUseCase,
private val isPasscodeInputUseCase: IsPasscodeInputUseCase,
private val clearAllDataUseCase: ClearAllDataUseCase,
#ApplicationContext private val context: Context
) : AndroidViewModel((context as App)) {
private val _openPin = MutableSharedFlow<Long>()
val openPin = _openPin.asSharedFlow()
// uptime in millis
private var time: Long = 0
private var restoreStatus = RestoreStatus.EMPTY
private var isPasscode = false
private var passCode = ""
init {
// get user status
}
private fun checkIfShouldLock() {
viewModelScope.launch {
isPasscode = withContext(IO) {
isPasscodeInputUseCase()
}
val userHasAccount = (restoreStatus == RestoreStatus.ID_SUBMISSION
|| restoreStatus == RestoreStatus.TERMS_AND_CONDITION
|| restoreStatus == RestoreStatus.ACTIVATE_CARD
|| restoreStatus == RestoreStatus.FULL_NAME
|| restoreStatus == RestoreStatus.COMPLETED)
if (true)
_openPin.emit (System.currentTimeMillis() )
}
}
fun onResume() {
updatePasscode()
if (!isPasscode) {
time = 0
return
}
val now = SystemClock.elapsedRealtime()
when {
time == 0L -> {
// remember first value
time = now
}
// check is session expired
now - time > sessionExpiredTime -> {
time = now
when (restoreStatus) {
RestoreStatus.COMPLETED -> checkIfShouldLock()
RestoreStatus.EMPTY -> {}
else -> {}
}
}
else -> {
time = now
}
}
}
fun onPause() {
updatePasscode()
viewModelScope.launch {
delay(Constants.PASSCODE_DELAY)
if (!isPasscode) {
time = 0
return#launch
}
// start "timer"
time = SystemClock.elapsedRealtime()
}
}
private fun updatePasscode() {
viewModelScope.launch {
isPasscode = withContext(IO) {
isPasscodeInputUseCase()
}
}
}
fun logout() {
viewModelScope.launch {
withContext(Dispatchers.IO) {
clearAllDataUseCase()
}
}
}
companion object {
const val MAIN_VIEW_MODEL_TAG = "AppViewModel"
}
}
and here is my application class and how i try to access the viewmodel
#HiltAndroidApp
class App : Application(), Application.ActivityLifecycleCallbacks,
Configuration.Provider {
#Inject
lateinit var workerFactory: HiltWorkerFactory
override fun getWorkManagerConfiguration() =
Configuration.Builder()
.setWorkerFactory(workerFactory)
.build()
// uptime in millis
private var time: Long = 0
var appViewModel : AppViewModel ?=null
var currentActivity : String ?=null
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
appViewModel = ViewModelProvider.AndroidViewModelFactory(this).create(AppViewModel::class.java)
appViewModel?.openPin?.onEach {
// if (authToken.isNotEmpty())
when (currentActivity) {
SplashActivity::class.java.name,
PinActivity::class.java.name -> Unit
else -> {
startActivity(Intent(this, PinActivity::class.java).apply {
// flag of should end with result or not
// putExtra(Constants.IS_CAME_FROM_BACKGROUND, true)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
})
}
}
}
setupCrashlytics()
if (BuildConfig.DEBUG)
Timber.plant(Timber.DebugTree())
else
Timber.plant(CrashReportingTree())
DyScan.init(this, Constants.DYSCAN_API_KEY)
registerActivityLifecycleCallbacks(this)
}
private fun setupCrashlytics() {
with(FirebaseCrashlytics.getInstance()) {
setCrashlyticsCollectionEnabled(!BuildConfig.DEBUG)
}
}
private fun isDeviceRooted(): Boolean {
var process: Process? = null
return try {
process = Runtime.getRuntime().exec("su")
true
} catch (e: Exception) {
Timber.i(e, "Rooted device command exception")
false
} finally {
if (process != null) {
try {
process.destroy()
} catch (e: Exception) {
Timber.i(e, "Rooted device command close exception")
}
}
}
}
private fun hideSystemBars(activity: Activity) {
val windowInsetsController =
ViewCompat.getWindowInsetsController(activity.window.decorView) ?: return
windowInsetsController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE
windowInsetsController.hide(WindowInsetsCompat.Type.navigationBars())
}
override fun onActivityCreated(activity: Activity, p1: Bundle?) {
currentActivity = activity.localClassName
if (isDeviceRooted()) {
Toast.makeText(
activity,
getString(R.string.rooted_device_message),
Toast.LENGTH_SHORT
).show()
activity.finishAffinity()
}
}
override fun onActivityStarted(p0: Activity) {
appViewModel?.onResume()
}
override fun onActivityResumed(p0: Activity) {}
override fun onActivityPaused(p0: Activity) {}
override fun onActivityStopped(activity: Activity) {
appViewModel?.onPause()
}
override fun onActivitySaveInstanceState(p0: Activity, p1: Bundle) {}
override fun onActivityDestroyed(p0: Activity) {}
}
i keep getting RuntimeException: Cannot create an instance of class x.x.AppViewModel
2022-03-08 22:29:44.189 10889-10889/com.x.x E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.x.x, PID: 10889
java.lang.RuntimeException: Unable to create application com.x.x.App: java.lang.RuntimeException: Cannot create an instance of class com.x.x.AppViewModel
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6991)
at android.app.ActivityThread.access$1700(ActivityThread.java:274)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2093)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:233)
at android.app.ActivityThread.main(ActivityThread.java:8010)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978)
Caused by: java.lang.RuntimeException: Cannot create an instance of class com.x.x.AppViewModel
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:230)
at com.x.x.App.onCreate(App.kt:54)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1208)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6986)
at android.app.ActivityThread.access$1700(ActivityThread.java:274)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2093)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:233)
at android.app.ActivityThread.main(ActivityThread.java:8010)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978)
Caused by: java.lang.NoSuchMethodException: com.x.x.AppViewModel.<init> [class android.app.Application]
at java.lang.Class.getConstructor0(Class.java:2332)
at java.lang.Class.getConstructor(Class.java:1728)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:228)
at com.x.x.App.onCreate(App.kt:54)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1208)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6986)
at android.app.ActivityThread.access$1700(ActivityThread.java:274)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2093)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:233)
at android.app.ActivityThread.main(ActivityThread.java:8010)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978)
What i am doing wrong in this implementation ?
Is this the right way to implement a viewModel scoped to application ?
From what I can tell, something is trying to call a no argument constructor on your ViewModel, but you have only defined a constructor that takes arguments.
You have arguments in viewmodel constructor. You will have to extend viewmodel factory and handle the parameters passed. Later pass the required parameter values to custom viewmodel factory instance. Finally use the custom view model factory instance in ViewModelProvider.AndroidViewModelFactory(this ,customInstance).create (AppViewModel::class.java)
I am trying to test myself in android development. For that I am trying to make a social media app with the help of firebase (using firebase authentication), but the problem is. After I login with every credentials correct, its is not showing the next activity screen which is meant to be opened. I don't know what mistake did I make. Here is the code for loginAcitivity screen:
class LoginActivity : AppCompatActivity() {
private val firebaseAuth = FirebaseAuth.getInstance()
private val firebaseAuthListener = FirebaseAuth.AuthStateListener {
val user = firebaseAuth.currentUser?.uid
user?.let {
startActivity(HomeActivity.newIntent(this))
finish()
}
}
#SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
setTextChangeListener(emailET, emailTIL)
setTextChangeListener(passwordET, passwordTIL)
loginProgressLayout.setOnTouchListener { v :View, event :MotionEvent -> true }
}
private fun setTextChangeListener(et: EditText, til: TextInputLayout) {
et.addTextChangedListener(object: TextWatcher{
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
til.isErrorEnabled = false
}
})
}
fun onLogin(v: View){
var proceed = true
if(emailET.text.isNullOrEmpty()){
emailTIL.error = "Email is required"
emailTIL.isErrorEnabled = true
proceed = false
}
if(passwordET.text.isNullOrEmpty()){
passwordTIL.error ="Password is required"
passwordTIL.isErrorEnabled = true
proceed = false
}
if(proceed){
loginProgressLayout.visibility = View.VISIBLE
firebaseAuth.signInWithEmailAndPassword(emailET.text.toString(), passwordET.text.toString())
.addOnCompleteListener { task: Task<AuthResult> ->
if (!task.isSuccessful) {
loginProgressLayout.visibility = View.GONE
Toast.makeText(this#LoginActivity, "Login error: Either the username or password is wrong.", Toast.LENGTH_SHORT).show()
}
}.addOnFailureListener{e: Exception ->
e.printStackTrace()
loginProgressLayout.visibility = View.GONE
}
}
}
fun goToSignUp(v: View){
startActivity(SignUpActivity.newIntent(this))
finish()
}
override fun onStart() {
super.onStart()
firebaseAuth.addAuthStateListener { firebaseAuthListener }
}
override fun onStop() {
super.onStop()
firebaseAuth.removeAuthStateListener { firebaseAuthListener }
}
companion object{
fun newIntent(context: Context) = Intent(context, LoginActivity::class.java)
}
}
To test out that authentication is working or not I place a button in the activity to logout.
Help me please it's been week since I am stuck on it.
You were using lambda and in there you were no doing any task.
override fun onStart() {
super.onStart()
firebaseAuth.addAuthStateListener(firebaseAuthListener)
}
override fun onStop() {
super.onStop()
firebaseAuth.removeAuthStateListener(firebaseAuthListener)
}
I have a function for the user's login.
But it is suspended.
I try to get its return value, but I can't.
Here's what I tried to do
Code
class LoginViewModel #ViewModelInject constructor(private val remoteDataSource: OrderRemoteDataSource) :
ViewModel() {
private fun areValidCredentials(username: String?, password: String?): Boolean {
return username != null && password != null && username.length > 4 && password.length > 4
}
suspend fun login(username: String?, password: String?): Boolean {
return suspendCoroutine { it ->
val valid = areValidCredentials(username, password)
if (valid) {
// call finish so login activity won't show up after back button clicked in home fragment
try {
viewModelScope.launch {
//TODO CHECK if error code
val loginResponse =
remoteDataSource.login(LoginRequest(username!!, password!!))
if (loginResponse.status == Resource.Status.SUCCESS) {
val jwtToken = loginResponse.data?.jwtToken
if (!jwtToken.isNullOrEmpty()) {
sessionManager.saveAuthToken(jwtToken!!)
//ERROR!
it.resume(true)
}
}
}
} catch (e: Exception) {
Log.i("[LoginActivity]", e.localizedMessage!!)
it.resume(false)
e.printStackTrace()
}
} else {
Toast.makeText(
LOGIN_ACTIVITY,
"Username and password must be at least 5 letters long",
Toast.LENGTH_SHORT
).show()
}
it.resume(false)
}
}
}
And i call it
#AndroidEntryPoint
class LoginFragment : Fragment() {
private val mViewModel: LoginViewModel by viewModels()
private lateinit var navController: NavController
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.frg_login, container, false)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("[LoginFragment]", "onCreate fun started!")
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
navController = findNavController()
loginButton.setOnClickListener {
//TODO navigate to new fragmnet
lifecycleScope.launch {
mViewModel.login(
loginUsernameText.text.toString(),
loginPasswordText.text.toString()
)
}
}
}
And i have error
E/AndroidRuntime: FATAL EXCEPTION: main
Process: ru.gkomega.navigation, PID: 11863
java.lang.IllegalStateException: Already resumed
at kotlin.coroutines.SafeContinuation.resumeWith(SafeContinuationJvm.kt:45)
at ru.gkomega.maumarket.ui.login.LoginViewModel$login$$inlined$suspendCoroutine$lambda$1.invokeSuspend(LoginViewModel.kt:40)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) I/chatty:
uid=10163(ru.gkomega.navigation) identical 16 lines W/mega.navigatio:
Got a deoptimization request on un-deoptimizable method
java.lang.Class java.lang.Class.classForName(java.lang.String,
boolean, java.lang.ClassLoader) I/Process: Sending signal. PID: 11863
SIG: 9 Disconnected from the target VM, address: 'localhost:58264',
transport: 'socket'
I don't know much about coroutines so they're probably the problem
You are resuming the coroutine regardless of the request happened or not, it failed or not.
suspend fun login(username: String?, password: String?): Boolean = suspendCoroutine { cont ->
if (areValidCredentials(username, password)) {
try {
viewModelScope.launch {
val loginResponse = remoteDataSource.login(LoginRequest(username!!, password!!))
val jwtToken = loginResponse.data?.jwtToken
if (loginResponse.status == Resource.Status.SUCCESS && !jwtToken.isNullOrEmpty()) {
sessionManager.saveAuthToken(jwtToken!!)
cont.resume(true)
} else cont.resume(false) // <-- Don't forget
}
} catch (e: Exception) {
Log.i("[LoginActivity]", e.localizedMessage!!)
cont.resume(false)
e.printStackTrace()
}
} else {
Toast.makeText(
LOGIN_ACTIVITY,
"Username and password must be at least 5 letters long",
Toast.LENGTH_SHORT
).show()
cont.resume(false) // <-- Put it right here.
}
// cont.resume(false) // <-- Not here
}
Try this code!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
navController = findNavController()
loginButton.setOnClickListener {
//TODO navigate to new fragment
val isAuth = mViewModel.login(
loginUsernameText.text.toString(),
loginPasswordText.text.toString()
)
if (isAuth) {
val startMainAction =
LoginFragmentDirections.actionStartMain(loginUsernameText.text.toString())
navController.navigate(startMainAction)
}
}
}
And this fragment on viewModel
fun login(username: String?, password: String?): Boolean {
var isAuth = false
val valid = areValidCredentials(username, password)
if (valid) {
// call finish so login activity won't show up after back button clicked in home fragment
try {
//TODO CHECK if error code
runBlocking {
val loginResponse = remoteDataSource.login(LoginRequest(username!!, password!!))
if (loginResponse.status == Resource.Status.SUCCESS) {
val jwtToken = loginResponse.data?.jwtToken.toString()
if (!jwtToken.isNullOrEmpty()) {
sessionManager.saveAuthToken(jwtToken)
isAuth = true
}
}
}
} catch (e: Exception) {
Log.i("[LoginActivity]", e.localizedMessage!!)
e.printStackTrace()
}
I'm not sure if this code is correct, but it works!
In my Fragment, I'm trying to fetch data from Firebase Database using coroutines where data is retrieving properly. Here is my code
#ExperimentalCoroutinesApi //Fragment Class code
override fun onStart() {
super.onStart()
checkOutViewModel.viewModelScope.launch {
try{
if (isActive){
checkOutViewModel.getCartDataFromFirebaseNetwork().collect{
tempList.add(it)
}
}
}catch (ex : Exception){
Log.d("exception message",ex.cause?.message!!) //Fatal Exception: Main
}
orderListAdapter?.submitList(tempList)
binding.progress.visibility = View.GONE
binding.recycler.visibility = View.VISIBLE
}
}
#ExperimentalCoroutinesApi //Viewmodel class code
suspend fun getCartDataFromFirebaseNetwork()= firebaseNetwork.getCartFromFirebase()
#ExperimentalCoroutinesApi //Repository class code
suspend fun getCartFromFirebase() = callbackFlow<Cart> {
ensureActive()
val counterList = myFlow.toList()
val itemList = myFlow.mapBasketToItemsList().toList()
val pairs = myFlow.mapBasketListToQuantity().toList()
if(itemList.isNotEmpty() && pairs.isNotEmpty()){
for ((current,item) in itemList.withIndex()) {
val cart = Cart(counterList[current].basketId!!,item.id!!,item.url!!,item.name!!,pairs[current].first,pairs[current].second,counterList[current].itemCounter!!,pairs[current].second)
offer(cart)
}
channel.close()
}
}
#ExperimentalCoroutinesApi
val myFlow = callbackFlow<Basket> {
databaseReference.child("Cart").child(getCurrentUserUid())
.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (dataSnapshot.exists()) {
for (data in dataSnapshot.children) {
val basket = Basket()
basket.basketId = data.key
basket.itemId = data.child("itemId").value as String
basket.itemCounter = data.child("itemCounter").value as String
basket.itemWeight = data.child("itemWeight").value as String
offer(basket)
}
channel.close()
}
}
})
awaitClose()
}
#ExperimentalCoroutinesApi
private fun Flow<Basket>.mapBasketToItemsList() : Flow<Items> = map{basket ->
suspendCoroutine<Items> {continuation ->
databaseReference.child("Items").child(basket.itemId!!)
.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (dataSnapshot.exists()) {
val items = dataSnapshot.getValue(Items::class.java)!!
continuation.resume(items)
}
}
})
}
}
#ExperimentalCoroutinesApi
private fun Flow<Basket>.mapBasketListToQuantity() : Flow<Pair<String,String>> = map{basket ->
suspendCoroutine<Pair<String,String>> {continuation ->
databaseReference.child("Quantities").child(basket.itemId!!)
.child(basket.itemWeight!!)
.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (dataSnapshot.exists()) {
val key = dataSnapshot.key
val value = dataSnapshot.value as String
val myPair = Pair(key!!, value)
continuation.resume(myPair)
}
}
})
}
}
Edited:
This is my Navigation Flow of Fragments
OnBoarding-Authentication-MainFragment-CheckItemListFragment
override fun onStart() { //OnBoarding Fragment
super.onStart()
try {
if(viewModel.checkAuth()){
updateUI()
}
}catch (ex : Exception){
println("In onBoarding Fragment")
Log.d("exception message",ex.cause?.message!!)
}
}
override fun onStart() { //Authentication Fragment
super.onStart()
try {
if(mAuth.currentUser == null){
showShortToast("Please Login")
}else{
updateUI()
}
}catch (ex : Exception){
println("In authentication Fragment")
Log.d("exception message",ex.cause?.message!!)
}
}
override fun onStart() { //MainFragment
super.onStart()
try {
if(mainFragmentViewModel.checkSignIn() == null)
findNavController().navigateUp()
binding.toolbar.add_to_cart.setOnClickListener {
it.findNavController().navigate(R.id.action_mainFragment_to_checkoutItemsList)
}
}catch (ex : Exception){
println("In Main Fragment")
Log.d("exception",ex.message!!)
}
}
#ExperimentalCoroutinesApi
override fun onStart() { //CheckItemList Fragment
super.onStart()
try {
binding.addToCart.setOnClickListener {
checkOutViewModel.viewModelScope.launch {
val message = orderListAdapter?.getList()?.let { it1 -> checkOutViewModel.submitFinalCart(it1) }
if(message!!){
findNavController().navigate(R.id.action_checkoutItemsList_to_finalCarts)
}
}
}
viewLifecycleOwner.lifecycleScope.launch {
ensureActive()
checkOutViewModel.getCartDataFromFirebaseNetwork().collect {
tempList.add(it)
orderListAdapter?.submitList(tempList)
binding.progress.visibility = View.GONE
binding.recycler.visibility = View.VISIBLE
}
}
}catch (ex : Exception){
println("In checkItemList Fragment")
Log.d("exception message",ex.cause?.message!!)
}
}
Edited : My Logcat is :-
--------- beginning of crash
07-10 21:18:40.605 30715-30715/com.example.groceryapp E/AndroidRuntime: FATAL
EXCEPTION: main
Process: com.example.groceryapp, PID: 30715
f.d
at com.example.groceryapp.checkout.CheckoutItemsList$e.a(:73)
at f.z.k.a.a.b(:33)
at kotlinx.coroutines.u0.run(:334)
at kotlinx.coroutines.z0.k(:68)
at kotlinx.coroutines.r0.b(:354)
at f.z.i.b(:42)
at com.example.groceryapp.f.a$r$a$b.a(:262)
at com.google.firebase.database.m$a.a(:179)
at com.google.firebase.database.u.a0.a(:75)
at com.google.firebase.database.u.i0.d.a(:63)
at com.google.firebase.database.u.i0.g$a.run(:55)
at android.os.Handler.handleCallback(Handler.java:742)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5603)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:774)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:652)
This is how i used my Try Catch block in every Fragments to handle this issue but it is also not working at all. I'm also using isActive method to check whether the job is still active or not before retrieving any data. I get "Fatal Exception: Main, Job was Cancelled" if i pressed back button before recyclerview shows the data. This exception only comes if i use callback flow. Is there any way to handle this issue or is it a bug in callback flow?. So far I couldn't find any possible answer that will solve my issue. Please tell me how do i fix it?
I faced with the same issue before and here is my solution with an extension of SendChannel
fun <T> SendChannel<T>.offerCatching(element: T): Boolean {
return runCatching { offer(element) }.getOrDefault(false)
}
and when emit event just call offerCatching
Why you launch coroutine in fragment onStart with viewModelScope ?
in fragment/activity you should use lifecycleScope.
see here for more details.
Wrap offer() method into try..catch and capture CancellationException. You may create an extension function to use across the application where using offer() method.
My application crash when I logout from Firebase. I checked the logcat and it shows me the following stack trace.
io.reactivex.exceptions.UndeliverableException: java.lang.Throwable: Permission denied
at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:349)
at io.reactivex.internal.operators.observable.ObservableCreate$CreateEmitter.onError(ObservableCreate.java:74)
at messenger.tarang.com.messenger.allusers.AllUsers$loadUsers$1$1.onCancelled(AllUsers.kt:78)
at com.google.android.gms.internal.zzecw.zza(Unknown Source)
at com.google.android.gms.internal.zzehy.zzbyc(Unknown Source)
at com.google.android.gms.internal.zzeig.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:742)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:5527)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
Caused by: java.lang.Throwable: Permission denied
at messenger.tarang.com.messenger.allusers.AllUsers$loadUsers$1$1.onCancelled(AllUsers.kt:78)
at com.google.android.gms.internal.zzecw.zza(Unknown Source)
at com.google.android.gms.internal.zzehy.zzbyc(Unknown Source)
at com.google.android.gms.internal.zzeig.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:742)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:5527)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
Here is the code where the problem arises.
Observable.create<DataSnapshot>{ emitter ->
databaseReference
?.child("Users")
?.addChildEventListener(object : ChildEventListener{
override fun onCancelled(p0: DatabaseError?) {
if(!emitter.isDisposed){
emitter.onError(Throwable(p0.message))
}
}
override fun onChildMoved(p0: DataSnapshot?, p1: String?) {
}
override fun onChildChanged(p0: DataSnapshot?, p1: String?) {
}
override fun onChildAdded(p0: DataSnapshot?, p1: String?) {
if(!emitter.isDisposed)
emitter.onNext(p0!!)
}
override fun onChildRemoved(p0: DataSnapshot?) {
}
})
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<DataSnapshot>{
override fun onComplete() {
}
override fun onNext(t: DataSnapshot) {
val userModel = t.getValue(UserModel::class.java)
userModel?.uid = t.key
userAdapter?.addData(userModel!!)
}
override fun onSubscribe(d: Disposable) {
compositeDisposable?.add(d)
}
override fun onError(e: Throwable) {
e.printStackTrace()
}
})
Below is my Account Settings class where i am performing logout action.If i comment emitter.onError()in above code then i don't get any exceptions.
class AccountSettings internal constructor(): AppCompatActivity(), View.OnClickListener {
var toolbar : Toolbar ?= null
var toolbar_text : TextView ?= null
var logout_text : TextView ?= null
var firebaseAuth : FirebaseAuth ?= null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.account_settings)
initialize()
}
override fun onStart() {
super.onStart()
logout_text?.setOnClickListener(this)
}
fun initialize(){
firebaseAuth = FirebaseAuth.getInstance()
logout_text = findViewById(R.id.logout_text)
toolbar = findViewById(R.id.toolbar)
toolbar_text = toolbar?.findViewById(R.id.toolbar_text1)
toolbar_text?.setText("Account Settings")
toolbar_text?.visibility= View.VISIBLE
setSupportActionBar(toolbar)
}
fun logout() {
try {
firebaseAuth?.signOut()
displayMessage("logout successfully")
goToMainActivity()
}
catch(ex : Exception){
ex.printStackTrace()
displayMessage("you are not connected to Internet")
}
}
fun goToMainActivity() {
var intents = Intent (this,CheckAuthenticate::class.java)
intents.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intents)
finish()
}
fun displayMessage(message: String) {
Toast.makeText(this,message,Toast.LENGTH_SHORT).show()
}
override fun onClick(p0: View?) {
when(p0?.id){
R.id.logout_text ->{
logout()
}
}
}
override fun onDestroy() {
super.onDestroy()
}
}
What should i do to make it work? How should i properly handle this exception so that my application does not crash? Please help anyone...
You need to handle UndeliverableException. Add to your Application onCreate():
RxJavaPlugins.setErrorHandler(error -> {
//Log error or just ignore it
});