NoSuchMethodError: No virtual method getInsetsController()

Viewed 4162

I upgrade my app to SDK 30. I saw that FLAG_FULLSCREEN deprecated. Then, i changed the code with this;

final WindowInsetsController insetsController = getWindow().getInsetsController();
if (insetsController != null) {
    insetsController.hide(WindowInsets.Type.statusBars());
}

but I am getting this error when i try to run my app on API 26.

java.lang.NoSuchMethodError: No virtual method getInsetsController()Landroid/view/WindowInsetsController; in class Landroid/view/Window; or its super classes (declaration of 'android.view.Window' appears in /system/framework/framework.jar:classes2.dex)
3 Answers

Google is currently working on a Compat version of WindowInsetsContrloller. This way, you won't need to branch if/else by android API level (as presented in @PerracoLabs's answer). On Compat version of WindowInsetsContrloller we don't need to use getWindow().setFlags() because window.insetsController?.hide() will work on all android versions.

Update:

They already made it - class androidx.core.view.WindowInsetsControllerCompat. You'll need to use androidx.core 1.5.0-alpha02 or greater.

My code example:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    setContentView(R.layout.activity_main)

    WindowCompat.setDecorFitsSystemWindows(window, false)

    hideSystemBars()
}

private fun hideSystemBars() {
    val insetsControllerCompat = WindowInsetsControllerCompat(window, window.decorView)
    insetsControllerCompat.systemBarsBehavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
    insetsControllerCompat.hide(systemBars())
}

private fun showSystemBars() {
    val insetsControllerCompat = WindowInsetsControllerCompat(window, window.decorView)
    insetsControllerCompat.show(systemBars())
}

When finding deprecation warnings you must perform API-level {if /else} condition branching, to handle both scenarios, so, new code for newer API levels / old code for older API levels.

The deprecation warning will still appear if you target a high API level above the deprecation level, and is optional to suppress it, and also valid to leave the warning to easily spot it for future potential removal. In the next example it is suppressed.

Note that Google may offer you in some cases Compat libraries, which internally perform the necessary API branching, this is always the most desirable solution when a Compat library for a developer's specific issue is available.

For your specific case you can do as next:

Java

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    final WindowInsetsController controller = getWindow().getInsetsController();
    
    if (controller != null)
        controller.hide(WindowInsets.Type.statusBars());
} 
else {
    //noinspection deprecation
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
                         WindowManager.LayoutParams.FLAG_FULLSCREEN);
}

Kotlin

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        window.insetsController?.hide(WindowInsets.Type.statusBars())
}
else {
    @Suppress("DEPRECATION")
    window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN)
}

Update:

Latest version is (FYI):

implementation 'androidx.core:core-ktx:1.5.0-alpha05'

Related