0

I've encountered a small issue when creating an Alert dialog in a Fragment. The following is the error thrown in the Logcat:

2020-07-26 11:21:47.425 20063-20063/com.example.MyApp E/WindowManager: android.view.WindowLeaked: Activity com.example.MyApp.MainActivity has leaked window DecorView@b9684c5[MainActivity] that was originally added here
        at android.view.ViewRootImpl.<init>(ViewRootImpl.java:769)
        at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:440)
        at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:95)
        at android.app.Dialog.show(Dialog.java:473)
        at com.example.MyApp.ScannerFragment.onCreateView(ScannerFragment.kt:44)
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
        at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2224)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
        at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:237)
        at android.app.ActivityThread.main(ActivityThread.java:8125)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)

I've tried referring to this question which explained that this error may appear possibly due to showing a dialog after an Activity was exited, not calling dismiss() before exiting, or another possibility.

In my context, however, I'm not sure on how to apply the solutions suggested in my context. I'm showing the Alert dialog on a Fragment, ScannerFragment, that is related to an Activity, MainActivity, through a Bottom Navigation menu. The following includes the code for the related files:

ScannerFragment.kt

package com.example.MyApp

import android.Manifest
import android.content.DialogInterface
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat
import androidx.core.app.ActivityCompat.requestPermissions
import androidx.fragment.app.Fragment


class ScannerFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            val builder: AlertDialog.Builder? = this.let {
                AlertDialog.Builder(requireActivity())
            }
            builder
                ?.setMessage(R.string.camera_unauthorisedMessage)
                ?.setTitle(R.string.camera_unauthorisedTitle)
                ?.apply {
                    setPositiveButton("OK",
                        DialogInterface.OnClickListener { dialog, _ ->
                            requestPermissions(requireActivity(), arrayOf(Manifest.permission.CAMERA), 1111)
                            dialog.dismiss()
                        })
                }

            builder?.create()?.show() // Line 44 - error occurs here
        } else {
            Log.e("DB", "PERMISSION GRANTED")
        }

        return inflater.inflate(R.layout.fragment_scanner, container, false)
    }

}

MainActivity.kt

package com.example.MyApp

import android.Manifest
import android.content.DialogInterface
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.children
import androidx.navigation.findNavController
import androidx.navigation.ui.setupWithNavController
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Sets up the bottom navigation bar for usage
        initialiseBottomNav()
    }

    // Overrides the back button to prevent going back to StartActivity
    override fun onBackPressed() {}

    private fun initialiseBottomNav() {
        val navController = findNavController(R.id.main_navhostfragment)
        main_bottomnav.setupWithNavController(navController)
    }

}

If I were to refer to the question above, what are the steps that I would need to do to resolve this error? All help is greatly appreciated, thank you!

Arash
  • 21
  • 7

3 Answers3

0

This circumstance means your activity is finishing or your app is crashing somewhere else in your code, but then the open dialog leads to leak window. A tip can be checking your log (typically lines above the log you have shared) and see if there is any other exception/error happening earlier.

sajjad
  • 834
  • 6
  • 13
  • Thank you for your input! I'm not completely familiar with the Logcat, unfortunately - therefore, what should I look out for there? – Arash Jul 26 '20 at 05:52
  • Logcat is the window where you have copied the crash log from. So you just need to run your app again until it crashes. Then try to find the log before the window leak log. – sajjad Jul 26 '20 at 05:56
0

Firstly, I would suggest you to add your AlertDialog code in onViewCreated method of your fragment.

Second, you can add the following checking just before showing your AlertDialog:

if(!requireActivity().isFinishing)
  builder?.create()?.show()
0

This happening because dialog associated with the activity context use application context

val builder: AlertDialog.Builder? = activity?.applicationContext?.let { AlertDialog.Builder(it) }
        if(builder != null) {
            builder
                    .setMessage("")
                    ?.setTitle("R.string.camera_unauthorisedTitle")
                    ?.apply {
                        setPositiveButton("OK",
                                DialogInterface.OnClickListener { dialog, _ ->
                                    requestPermissions(requireActivity(), arrayOf(Manifest.permission.CAMERA), 1111)
                                    dialog.dismiss()
                                })
                    }

            builder.create().show() // Line 44 - error occurs here
        }
alokHarman
  • 289
  • 1
  • 8