Search code examples
androidkotlinandroid-alertdialog

Android alert dialog glitch


I cannot figure this strange behaviour out.

This randomly happens on some device and always on a Honor 9 STF-L9 (the one on the gif animation).

If you look at this gif, you can see that coming back from the pick chooser, the dialog is visible again, even if no one is showing it (see the full image gif by clicking on it to see the video).

enter image description here

I've a single Activity application (I use the new Navigation jetpack component) and I have a custom AlertDialog in my MainActivity:

class MainActivity : AppCompatActivity() {

    private lateinit var appBarConfiguration: AppBarConfiguration
    private lateinit var binding: ActivityMainBinding

    private lateinit var inflater: LayoutInflater
    private lateinit var dialogView: View
    private lateinit var messageTextView: TextView
    private val progressHud: AlertDialog by lazy {
        val dialogBuilder =
            AlertDialog.Builder(this, R.style.ProgressHudTheme)

        messageTextView.visibility = View.GONE
        dialogBuilder.setView(dialogView)
        dialogBuilder.setCancelable(false)
        dialogBuilder.create()
    }

    fun showProgressHud(message: String?) {
        messageTextView.visibility = View.GONE
        message?.let {
            messageTextView.text = it
            messageTextView.visibility = View.VISIBLE
        }
        progressHud.show()
    }

    fun hideProgressHud() {
        progressHud.hide()
    }

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

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        setSupportActionBar(binding.toolbar)

        val navController = findNavController(R.id.nav_host_fragment_content_main)
        appBarConfiguration = AppBarConfiguration(navController.graph)
        setupActionBarWithNavController(navController, appBarConfiguration)

        binding.fab.setOnClickListener { view ->
            dispatchChoosePictureFromGalleryAppIntentIntent()
        }

        setupProgressHud()
    }

    private fun dispatchChoosePictureFromGalleryAppIntentIntent() {
        Intent(
            Intent.ACTION_PICK,
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI
        ).apply {
            putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
            resolveActivity(packageManager)?.also {
                requestImageChooserLauncher.launch(this)
            }
        }
    }


    private var requestImageChooserLauncher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        val resultCode = result.resultCode
        val data = result.data
        // TODO ...
    }

    private fun setupProgressHud() {
        inflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        dialogView = inflater.inflate(R.layout.progress_hud, null)
        messageTextView = dialogView.findViewById(R.id.progressHudTextView)
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        // Inflate the menu; this adds items to the action bar if it is present.
        menuInflater.inflate(R.menu.menu_main, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        return when (item.itemId) {
            R.id.action_settings -> true
            else -> super.onOptionsItemSelected(item)
        }
    }

    override fun onSupportNavigateUp(): Boolean {
        val navController = findNavController(R.id.nav_host_fragment_content_main)
        return navController.navigateUp(appBarConfiguration)
                || super.onSupportNavigateUp()
    }
}

The Dialog is shown and hidden this way in the FirstFragment:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    binding.buttonFirst.setOnClickListener {
        (activity as? MainActivity)?.showProgressHud("Loading...")
        Handler().postDelayed({
            findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
            (activity as? MainActivity)?.hideProgressHud()
        }, 5000)
    }
}

And you can find a complete working example here: https://github.com/shadowsheep1/android-alert-dialog-glitch

I still haven't figure why this happens out.

If someone had encountered this before or have any clues would be appreciated.


Solution

  • Try replacing

    progressHud.hide() 
    

    by

    progressHud.dismiss().
    

    That should work fine.

    There's a more important reason behind using dismiss() over hide(): using hide() could cause a Leaked Window Error, as it does not really remove the view, just hides it, and then if you finish the activity that might cause leakage.