In my app I use this method to detect the keyboard on screen. It works perfectly on api 28+ But once I go below api 28 it starts to cause crashes.
private fun isKeyboardOpen() {
window?.decorView?.setOnApplyWindowInsetsListener { v, insets ->
val systemWindowInsets = insets.inset(0,0,0,200)
imeVisible = ViewCompat.getRootWindowInsets(requireView())?.getInsets(ime())
if(imeVisible != null){
if(imeVisible?.bottom!! > 0){
ivWeatherIcon1.visibility = View.INVISIBLE
} else {
ivWeatherIcon1.visibility = View.VISIBLE
}
}
systemWindowInsets
}
}
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.app, PID: 8062
java.lang.NoSuchMethodError: No virtual method inset(IIII)Landroid/view/WindowInsets; in class Landroid/view/WindowInsets; or its super classes (declaration of 'android.view.WindowInsets' appears in /system/framework/framework.jar!classes2.dex)
at com.app.framework.presentation.workouts.reframe.Workout$isKeyboardOpen$1.onApplyWindowInsets(WorkoutMoodReframe.kt:881)
at android.view.View.dispatchApplyWindowInsets(View.java:9225)
at android.view.ViewGroup.dispatchApplyWindowInsets(ViewGroup.java:6929)
at android.view.ViewRootImpl.dispatchApplyInsets(ViewRootImpl.java:1568)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1812)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1392)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6752)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
at android.view.Choreographer.doCallbacks(Choreographer.java:723)
at android.view.Choreographer.doFrame(Choreographer.java:658)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Is there a way to make this method work back to api 23?
Obviously, keyboard appearance support does not support api <28 yet, so until backward compatibility for getInsets (ime ()) is released - you can use the following code:
private fun isKeyboardOpen() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// your code above
} else {
// code from source below
}
}
How to check visibility of software keyboard in Android?
Related
I am getting an error the first time the user sign in, however, there is no error the second time the user open the app
from the logcat the awaiClose function is triggered. so where is the error come from?!
The code
val userIdFlow = callbackFlow {
val listener = FirebaseAuth.AuthStateListener { firebaseAuth ->
Timber.tag("Auth_Util").d("Changed")
firebaseAuth.currentUser?.let {
Timber.tag("Auth_Util").d("user exist, id = ${it.uid}")
trySend(it.uid) // the line mentioned in the error message (AuthUtil.kt:38)
}
}
auth.addAuthStateListener(listener)
awaitClose {
Timber.tag("Auth_Util").d("Closed")
auth.removeAuthStateListener(listener)
}
}
The Logcat
2022-10-13 16:00:11.541 6972-6972 Auth_Util com.hussienFahmy.myGpaManager D Changed
2022-10-13 16:00:11.541 6972-6972 Auth_Util com.hussienFahmy.myGpaManager D user exist, id = g11Hbz2EUWXGSE0WnbcF2nJRUPQ2
2022-10-13 16:00:11.543 6972-6972 Auth_Util com.hussienFahmy.myGpaManager D Closed
2022-10-13 16:00:11.716 6972-6972 AndroidRuntime com.hussienFahmy.myGpaManager E FATAL EXCEPTION: main
Process: com.hussienFahmy.myGpaManager, PID: 6972
java.lang.IllegalStateException: 'awaitClose { yourCallbackOrListener.cancel() }' should be used in the end of callbackFlow block.
Otherwise, a callback/listener may leak in case of external cancellation.
See callbackFlow API documentation for the details.
at kotlinx.coroutines.flow.CallbackFlowBuilder.collectTo(Builders.kt:343)
at kotlinx.coroutines.flow.internal.ChannelFlow$collectToFun$1.invokeSuspend(ChannelFlow.kt:60)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.EventLoop.processUnconfinedEvent(EventLoop.common.kt:69)
at kotlinx.coroutines.DispatchedTaskKt.resumeUnconfined(DispatchedTask.kt:245)
at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:161)
at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
at kotlinx.coroutines.CancellableContinuationImpl.completeResume(CancellableContinuationImpl.kt:513)
at kotlinx.coroutines.channels.AbstractChannel$ReceiveElement.completeResumeReceive(AbstractChannel.kt:908)
at kotlinx.coroutines.channels.ArrayChannel.offerInternal(ArrayChannel.kt:83)
at kotlinx.coroutines.channels.AbstractSendChannel.trySend-JP2dKIU(AbstractChannel.kt:155)
at kotlinx.coroutines.channels.ChannelCoroutine.trySend-JP2dKIU(Unknown Source:2)
at com.hussienFahmy.myGpaManager.network.AuthUtil$userIdFlow$1.invokeSuspend$lambda-1(AuthUtil.kt:38)
at com.hussienFahmy.myGpaManager.network.AuthUtil$userIdFlow$1.$r8$lambda$gz_nO4N2PXNldWwFNxezrd-NGHg(Unknown Source:0)
at com.hussienFahmy.myGpaManager.network.AuthUtil$userIdFlow$1$$ExternalSyntheticLambda0.onAuthStateChanged(Unknown Source:2)
at com.google.firebase.auth.zzk.run(com.google.firebase:firebase-auth##21.0.8:1)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:236)
at android.app.ActivityThread.main(ActivityThread.java:8057)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:620)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1011)
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}#1daddb6, Dispatchers.Main.immediate]
I have dialog fragment containes list of users so When my dialog fragment is showing and I change let's say the language or activate or disactivate dark mode or any other config change my dialog fragment dissmiss and lose state
so this how i create the dialog :
CheckableContactsDialog.newInstance(object : CheckableContactListener {
override fun onPositiveClick(selected: MutableList<String>) {
checkableContactsDialog?.dismiss()
if (mVCall != null) {
val (phones, phoneFlat) = extractPhonesNumberFromContacts(
context, selected
)
if (phones.isEmpty()) {
return
}
inviteNewUsers(phoneFlat)
}
}
override fun onNegativeClick() {
checkableContactsDialog?.dismiss()
}
})
After configchange like language change or activate or desactivate dark mode and trigger the onPositiveClick event and checkableContactsDialog?.dismiss() called this error appear
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.zetabox.totrapp, PID: 4368
java.lang.IllegalStateException: Fragment CheckableContactsDialog{58e7d9c} (77fb6c1e-6986-4eb0-8e35-c1ee51f4e0c9) not associated with a fragment manager.
at androidx.fragment.app.Fragment.getParentFragmentManager(Fragment.java:1040)
at androidx.fragment.app.DialogFragment.dismissInternal(DialogFragment.java:350)
at androidx.fragment.app.DialogFragment.dismiss(DialogFragment.java:307)
at com.google.android.material.bottomsheet.BottomSheetDialogFragment.dismiss(BottomSheetDialogFragment.java:47)
at com.zetabox.totrapp.ui.call.CallActivity$showAddUserDialog$1.onPositiveClick(CallActivity.kt:2123)
at com.zetabox.totrapp.ui.dialogs.CheckableContactsDialog.init$lambda-7(CheckableContactsDialog.kt:231)
at com.zetabox.totrapp.ui.dialogs.CheckableContactsDialog.$r8$lambda$BXYvl1NNrhMJYwo5PbYyZJ1LQtM(Unknown Source:0)
at com.zetabox.totrapp.ui.dialogs.CheckableContactsDialog$$ExternalSyntheticLambda0.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:7171)
at android.view.View.performClickInternal(View.java:7148)
at android.view.View.access$3500(View.java:802)
at android.view.View$PerformClick.run(View.java:27409)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7650)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:503)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
package com.example.absolutelydumb
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.InputType
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import kotlinx.android.synthetic.main.activity_main.*
//sets var to some random number and asks for a guess, giving feedback on proximity to answer
class MainActivity : AppCompatActivity() {
private val startButton: Button = findViewById(R.id.startButton)
private val submitButton: Button = findViewById(R.id.submit)
private val instructionsText: TextView = findViewById(R.id.instructionView)
private val response: EditText = findViewById(R.id.answerInput)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val startText: String = getString(R.string.startText)
startButton.text = startText
//TODO("Add autofillHints")
startButton.setOnClickListener {
numberGuess()
}
//TODO("Set text back to start after guessing is done")
}
fun numberGuess() {
response.inputType = InputType.TYPE_CLASS_NUMBER
val clickText: String = getString(R.string.clickText)
startButton.text = clickText
//TODO("Add autofillHints")
instructionsText.text = getString(R.string.instructions)
val randomNumber: Int = rand(0,10)
submitButton.setOnClickListener {
val responseText = Integer.parseInt(answerInput.text.toString())
if(responseText == randomNumber) {
instructionsText.text = getString(R.string.correctGuess)
} else {
instructionsText.text = getString(R.string.badGuess)
}
}
}
fun rand(start: Int, end: Int): Int {
//require(start <= end) { "Illegal Argument" }
return (start..end).random()
}
}
Above is the code that I've been writing. This is my first project, so I don't know what went wrong. I fixed a variable type problem in the numberGuess function but when I finished fixing it the app wouldn't open and the virtual device stated a "app keeps stopping" error.
Here is the Run log that lists off errors. The build log didn't have any errors.
07/09 19:58:05: Launching 'app' on phone1.
Install successfully finished in 1 s 266 ms.
$ adb shell am start -n "com.example.absolutelydumb/com.example.absolutelydumb.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Connected to process 5935 on device 'phone1 [emulator-5554]'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.absolutelydumb, PID: 5935
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.absolutelydumb/com.example.absolutelydumb.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2843)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference
at android.content.ContextWrapper.getApplicationInfo(ContextWrapper.java:159)
at android.view.ContextThemeWrapper.getTheme(ContextThemeWrapper.java:157)
at android.content.Context.obtainStyledAttributes(Context.java:675)
at androidx.appcompat.app.AppCompatDelegateImpl.createSubDecor(AppCompatDelegateImpl.java:692)
at androidx.appcompat.app.AppCompatDelegateImpl.ensureSubDecor(AppCompatDelegateImpl.java:659)
at androidx.appcompat.app.AppCompatDelegateImpl.findViewById(AppCompatDelegateImpl.java:479)
at androidx.appcompat.app.AppCompatActivity.findViewById(AppCompatActivity.java:214)
at com.example.absolutelydumb.MainActivity.<init>(MainActivity.kt:13)
at java.lang.Class.newInstance(Native Method)
at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:69)
at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:45)
at android.app.Instrumentation.newActivity(Instrumentation.java:1215)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2831)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
You cannot call findViewById before onCreate() or setContentView() is called. Since you are using findViewById at the declaration site of your four properties, it is being called at the time your Activity class is being instantiated, which is before onCreate is called.
There are two ways to handle this.
Use lateinit var and set the properties right after your call to setContentView():
private lateinit var startButton: Button
//...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button = findViewById(R.id.startButton)
//...
Use by lazy so it is only called when the property is first accessed, which will be after setContentView() is called:
private val startButton: Button by lazy { findViewById(R.id.startButton) }
Or you can use view binding, which gets rid of most of this boilerplate and is less error-prone. By error-prone, I mean you can call findViewById and accidentally search for a view that isn't present in the current layout and it will crash at runtime. View binding makes this impossible.
I have a crash in production since I've have release the ability to cast HLS video from my app to a Chromecast using the ExoPlayer Cast Extension.
It happens 100% on Android 9 and on a variety of devices (Xiaomi Redmi K20, Samsung
Galaxy S9, ZenFone Max Pro M2 etc...)
Here is my ExoPlayer cast extension implementation :
private fun initCast() {
mediaRouteButton = view?.findViewById(R.id.media_route_button)
CastButtonFactory.setUpMediaRouteButton(activity?.applicationContext, mediaRouteButton)
val castContext = CastContext.getSharedInstance()
}
private fun prepareCast(title: String) {
CastContext.getSharedInstance()?.let {
castPlayer = CastPlayer(it)
}
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
movieMetadata.putString(MediaMetadata.KEY_TITLE, title)
videoThumbnail?.let {
movieMetadata.addImage(WebImage(Uri.parse(it)))
}
val mediaInfo = MediaInfo.Builder(videoUrl)
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setContentType(MimeTypes.VIDEO_UNKNOWN)
.setMetadata(movieMetadata).build()
val mediaItems = arrayOf(MediaQueueItem.Builder(mediaInfo).build())
castPlayer?.setSessionAvailabilityListener(object : SessionAvailabilityListener {
override fun onCastSessionAvailable() {
castPlayer?.loadItems(mediaItems, 0, playerViewModel.getVideoPosition(), Player.REPEAT_MODE_OFF)
playerViewModel.pauseVideo()
}
override fun onCastSessionUnavailable() {
castPlayer?.currentPosition?.let {
playerViewModel.setVideoPosition(it)
playerViewModel.playVideo()
}
})
}
Here is the stacktrace :
Fatal Exception: java.lang.NullPointerException: Attempt to write to field 'boolean kj1.a' on a null object reference
at com.google.android.gms.internal.cast.zzka.zzhx(zzka.java:38)
at com.google.android.gms.internal.cast.zzmd.zza(zzmd.java:3)
at com.google.android.gms.internal.cast.zzms.zze(zzms.java:2518)
at com.google.android.gms.internal.cast.zzlf$zza.zziw(zzlf.java:20)
at com.google.android.gms.internal.cast.zzlf$zza.zziy(zzlf.java:41)
at com.google.android.gms.internal.cast.zzlf$zza.zzix(zzlf.java:23)
at com.google.android.gms.internal.cast.zzlf$zza.zziz(zzlf.java:42)
at com.google.android.gms.internal.cast.zzbc.zza(zzbc.java:1)
at com.google.android.gms.internal.cast.zzba.onSessionStarting(zzba.java:49)
at com.google.android.gms.cast.framework.zzag.zza(zzag.java:10)
at com.google.android.gms.cast.framework.zzz.dispatchTransaction(zzz.java:13)
at com.google.android.gms.internal.cast.zza.onTransact(zza.java:13)
at android.os.Binder.transact(Binder.java:667)
at androidx.mediarouter.media.MediaRouter$GlobalMediaRouter$MediaSessionRecord$1$2.b(MediaRouter.java:14)
at androidx.mediarouter.media.RegisteredMediaRouteProvider$Connection$1.a(RegisteredMediaRouteProvider.java:39)
at com.bumptech.glide.load.resource.gif.GifFrameLoader.b(GifFrameLoader.java:50)
at com.bumptech.glide.manager.TargetTracker.a(TargetTracker.java:42)
at androidx.media.AudioAttributesImpl.c(AudioAttributesImpl.java:21)
at androidx.fragment.app.FragmentState.a(FragmentState.java:11)
at androidx.preference.PreferenceGroupAdapter.onTransact(PreferenceGroupAdapter.java:5)
at android.os.Binder.transact(Binder.java:667)
at com.google.android.gms.internal.cast.zzb.zzb(zzb.java:21)
at com.google.android.gms.internal.cast.zzaf.zzd(zzaf.java:21)
at com.google.android.gms.internal.cast.zzaq.onRouteSelected(zzaq.java:4)
at androidx.mediarouter.media.MediaRouter$GlobalMediaRouter$CallbackHandler.invokeCallback(MediaRouter.java:3218)
at androidx.mediarouter.media.MediaRouter$GlobalMediaRouter$CallbackHandler.handleMessage(MediaRouter.java:3168)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6745)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I have open an issue in the ExoPlayer github and in Glide github without luck.
Do anybody have an idea of the cause of this crash ?
I am learning kotlin. i set button click handler in the xml as shown below in the code..when the button is clicked i call the method beginSearch(), but then the App crash and i receive the below posted
error.
please let me know how to fix this error.
Activity
private fun clickHandler(v : View?) : Unit {
when(v?.id) {
R.id.btnCheckSearchResult -> beginSearch("Trump")
}
}
button:
<Button
android:id="#+id/btnCheckSearchResult"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Check Search Result"
android:layout_below="#id/etSearchEntry"
android:onClick="clickHandler"/>
error:
--------- beginning of crash
2019-07-09 15:02:06.146 14883-14883/com.example.retrofitkotlin_v10 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.retrofitkotlin_v10, PID: 14883
java.lang.IllegalStateException: Could not find method clickHandler(View) in a parent or ancestor Context for android:onClick attribute defined on view class android.support.v7.widget.AppCompatButton with id 'btnCheckSearchResult'
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.resolveMethod(AppCompatViewInflater.java:424)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:381)
at android.view.View.performClick(View.java:6256)
at android.view.View$PerformClick.run(View.java:24701)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
java.lang.IllegalStateException: Could not find method
clickHandler(View) in a parent or ancestor Context for android:onClick
attribute defined on view class
android.support.v7.widget.AppCompatButton with id
'btnCheckSearchResult'
Remove android:onClick="clickHandler" from XML
And try with
btnCheckSearchResult.setOnClickListener {
beginSearch("Trump")
}
And
import kotlinx.android.synthetic.main.your_layout.*
Function must be public (or protected).
public fun clickHandler(v : View?) : Unit {
when(v?.id) {
R.id.btnCheckSearchResult -> beginSearch("Trump")
}
}
P.S - You could also use setOnClickListener as the other answers have pointed out.
Just use
btnCheckSearchResult.setOnClickListener {
beginSearch("Trump")
}
or
btnCheckSearchResult.setOnClickListener({
beginSearch("Trump")
})
make your function public
public fun clickHandler(v : View?) : Unit {
when(v?.id) {
R.id.btnCheckSearchResult -> beginSearch("Trump")
}
}