androidandroid-handlerandroid-threading

Android Handler With custom toast is working weird


I'm struggling to solve this problem when i use a custom toast message with Handler(Looper.getMainLooper()).post { message } to show it on screen. but It didn't work what i expected. In my case, i must use the combination.
(but I know if i don't use any Handler, it works well.)
So, What i want to do is to show the custom toast message and then finish a Activityimmediately.

First of all, I'll show you the resources.

custom_toast.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/tv_test_toast"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/ctm_bg_toast"
        android:gravity="center"
        android:padding="10dp"
        android:text="TextView"
        android:textColor="#FFFFFF"
        android:textSize="14dp" />

</LinearLayout>

ctm_bg_toast.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
    android:shape="rectangle">
    <solid android:color="#99000000"/>
    <corners android:radius="100dp"/>
    <padding android:left="10dp" android:top="7dp" android:right="10dp" android:bottom="7dp"/>
</shape>

and Please take a close look the following code snippet.

1. Using Handler

class TestActivity: AppCompatActivity() {

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

        Handler(Looper.getMainLooper()).post {
            val toast = Toast(this@TestActivity)
            toast.view = View.inflate(this@TestActivity, R.layout.custom_toast, null)
            ((toast.view?.findViewById(R.id.tv_test_toast)) as TextView).text = "test message"
            toast.setGravity(Gravity.CENTER, 0, Toast.LENGTH_SHORT)
            toast.show()
        }
        finish()
    }
}

this code does not show the custom toast message. i feel like the reason might be that i just finish the Activity while Handler is working asynchronously.

but the second code snippet works well. but i have no idea how it works.

2. Using two layered Handler

class TestActivity: AppCompatActivity() {

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

        Handler(Looper.getMainLooper()).post {
            Handler(Looper.getMainLooper()).post {
                val toast = Toast(this@TestActivity)
                toast.view = View.inflate(this@TestActivity, R.layout.custom_toast, null)
                ((toast.view?.findViewById(R.id.tv_test_toast)) as TextView).text = "test message"
                toast.setGravity(Gravity.CENTER, 0, Toast.LENGTH_SHORT)
                toast.show()
            }
        }
        finish()
    }
}

this code above is definitely working well. I just wrapped the Handler with another Handler. That's all!
So, What i want to know is how the two layered Handlers work well under the hood and What am i missing now?


Solution

  • It's almost definitely an issue with finish(). But there's a much simpler fix -- just run finish() inside the handler, right after you call toast.show()

    class TestActivity: AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            Handler(Looper.getMainLooper()).post {
                    val toast = Toast(this@TestActivity)
                    toast.view = View.inflate(this@TestActivity, R.layout.custom_toast, null)
                    ((toast.view?.findViewById(R.id.tv_test_toast)) as TextView).text = "test message"
                    toast.setGravity(Gravity.CENTER, 0, Toast.LENGTH_SHORT)
                    toast.show()
                    finish()
                }
            }
    }