使用 Thread.sleep 了解循环中的 toast

Understanding the toast in a loop using Thread.sleep

我是 Android 开发的新手。只是想测试以下代码,点击按钮执行一些任务。在日志显示循环结束后 Toast 弹出,因为 Toast 是异步的。但是

为什么会这样?据我所知,这一切都发生在 UI 线程中。如果只有一个线程,那么toast是如何异步工作的?

谢谢

button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int i=0;
                int j=0;
                Log.d("tag", "sec "+i);
                while(i++<15){
                    Log.d("tag", "sec "+i);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    Toast.makeText(getApplicationContext(),"num"+(j),Toast.LENGTH_SHORT).show();
                    j++;
                 }

            }
        });

Toast is asynchronous

首先,默认情况下 Toast 不是异步的。

why does it behave like this?

使用 Toast.LENGTH_SHORT 创建的 toast 的生命周期为 2 秒。现在,如果您的 UI 线程被锁定(因为 Thread.sleep),那么 toast 将不会出现在屏幕上。在显示之前它会 'die'。

如何让它按预期工作

运行 新创建的 Thread 中的整个块,并且只在主线程中创建和显示 Toast, 你需要按照以下几行做一些事情,

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                int i = 0;
                int j = 0;
                Log.d("tag", "sec " + i);
                while (i++ < 15) {
                    Log.d("tag", "sec " + i);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    final int finalJ = j;
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(getApplicationContext(), "num" + (finalJ), Toast.LENGTH_SHORT).show();
                        }
                    });
                    j++;
                }
            }
        }).start();
    }
});

您也可以通过使用 Handler.postDelayed

在不使用不同线程的情况下获得类似的结果
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        final int[] i = {0};
        final int[] j = {0};
        final int delayTime = 1000;

        Log.d("tag", "sec "+ i[0]);
        final Handler handler = new Handler();
        final Runnable runnable = new Runnable() {
            @Override
            public void run() {
                if(i[0]++<15) {
                    Log.d("tag", "sec " + i[0]);
                    Toast.makeText(getApplicationContext(), "num" + (j[0]), Toast.LENGTH_SHORT).show();
                    j[0]++;
                    handler.postDelayed(this, delayTime);
                }
            }
        };
        handler.postDelayed(runnable, delayTime);
    }
});

P.S - 切勿在主线程中使用 Thread.sleep,它会阻塞 UI 并导致糟糕的用户体验。