即使 CountDownTimer 过期,处理程序仍然是 运行

Handler is still running even though the CountDownTimer expires

我创建了一个处理程序来显示不同的骰子图像,而我的可运行对象是 运行。 通常,当我按下 "Roll" 按钮时,我的计时器从 3 开始倒计时,应用程序显示骰子的值。但有时,即使计时器到期,图像仍会继续变化。

我认为我的可运行程序仍在后台 运行。那么,Hhw 我可以在计时器到期时完全停止我的处理程序吗?

package com.basarballioz.dicerollerdroid;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.Random;

public class OneDiceActivity extends AppCompatActivity  {

TextView diceStatus;
Handler handler;
Runnable runnable;
ImageView diceView;
Button rollButton;
CountDownTimer rollTimer = null;
int diceNumber;
TextView diceResult;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.one_dice_activity);


    //MAKE APPLICATION FULLSCREEN
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);


    diceStatus = findViewById(R.id.diceStatus);
    rollButton = findViewById(R.id.rollButton);
    diceView = findViewById(R.id.diceView);
    diceResult = findViewById(R.id.diceResult);
    diceStatus.setText("Press Roll!");


    //Enable this ONLY IF you want to use OnClickListener method instead of onclick button
    /*diceView.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            //rollDice();
        }
    });*/
}


public void rollDice(View view) {

    diceStatus.setText("Rolling...");
    rollTimer = new CountDownTimer(3000, 1000) {
        @Override
        public void onTick(final long millisUntilFinished) {

            rollButton.setEnabled(false);
            handler = new Handler();
            runnable = new Runnable() {

            @Override
            public void run() {
                Random ranNumber = new Random();
                diceNumber = ranNumber.nextInt(6) + 1;

                switch (diceNumber) {
                    case 1:
                        diceView.setImageResource(R.drawable.dice1);
                        diceResult.setText("1");
                        break;
                    case 2:
                        diceView.setImageResource(R.drawable.dice2);
                        diceResult.setText("2");
                        break;
                    case 3:
                        diceView.setImageResource(R.drawable.dice3);
                        diceResult.setText("3");
                        break;
                    case 4:
                        diceView.setImageResource(R.drawable.dice4);
                        diceResult.setText("4");
                        break;
                    case 5:
                        diceView.setImageResource(R.drawable.dice5);
                        diceResult.setText("5");
                        break;
                    case 6:
                        diceView.setImageResource(R.drawable.dice6);
                        diceResult.setText("6");
                        break;
                    default:
                        break;
                }
                handler.postDelayed(runnable, 100);
            }
        };
        handler.post(runnable);
    }

        @Override
        public void onFinish() {
            rollButton.setEnabled(true);
            showDiceNumber();
            handler.removeCallbacks(runnable);
        }

    }.start();
}

public void showDiceNumber() {
    diceStatus.setText("Your dice is: ");
}

@Override
public void onBackPressed() {
    finish();
}

   @Override
   protected void onDestroy() {
   super.onDestroy();
   }

}

应用程序的 GitHub link:https://github.com/basarballioz/Dice-Rollerdroid

这一行

new CountDownTimer(3000, 1000) 

创建一个倒数计时器,在 1 秒后、2 秒后以及可能在 3 秒后调用 onTick(不相关但值得验证)。

onTick 的每次调用(2 或 3 次调用)中,您创建一个新的处理程序并分配给它:

handler = new Handler();

post它。每次每个处理程序完成时(现在是 2 或 3 个处理程序),它们会在 100 毫秒后重新安排:

handler.postDelayed(runnable, 100);

注意 运行nable 实例也被重新创建,这不是必需的。

onFinish 被调用时(在 2 或 3 个滴答声之后)- 有 2 或 3 个处理程序 运行每 100 毫秒重复一次。

只有最后一个处理程序或(第 2 个或第 3 个)被 onFinish 取消,最初的 1 或 2 个处理程序继续 运行。

图片...

您绝对不需要超过 1 个处理程序和 运行nable 实例 - 事实上,您根本不需要处理程序,因为 CountDownTimer 基本上已经这样做了。您是使用 CountDownTimer 还是仅使用带计数器的普通 Handler 由您决定。

如果希望在 1 秒延迟后每 100 毫秒改变一次骰子面(显示的值)持续 3 秒,然后将 onTick 更改为仅启动处理程序一次(或完全消除处理程序 - 请参阅建议的代码)。 (请注意,当前实施在 初始 1 秒后开始更改骰子 。)

(可能需要在 post 中说明您 真正 想要发生的事情。)

引用的库未正确实现。

我建议采用一种更简单的方法来消除 CountDownTimer 代码的冗余:

public void rollDice(View view) {

    diceStatus.setText("Rolling...");
    // Note the random is only created once.
    final Random ranNumber = new Random();
    rollButton.setEnabled(false);

    // updates every 100 millis after an initial 100milli delay.
    rollTimer = new CountDownTimer(3000, 100) {
        @Override
        public void onTick(final long millisUntilFinished) {

            diceNumber = ranNumber.nextInt(6) + 1;

            // use same switch statement as original post - sets the dice face.
        }

        @Override
        public void onFinish() {
            rollButton.setEnabled(true);
            showDiceNumber();
        }

    }.start();
}

如果你真的需要在滚动之前有 1 秒的初始延迟,那么不要立即 start() 而是添加类似的内容:

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        rollTimer.start();
    }
}, 1000);