运行 定时器完成或取消后的代码

Running a code after Timer finished or Canceled

跟随路径游戏说明:
在这个游戏中,屏幕上有一些方块是不可见的(在我们的例子中是 9 个),它们的随机序列开始出现在屏幕上(我们这里只显示 4 个)。并且用户必须按照方块在屏幕上显示的顺序 select 方块。

有什么问题?:
1. 不应允许用户在显示期间选择方块。我可以禁用按钮,但如何在计时器结束后启用它们?我找不到 postLaunch 或 timerCanceled 事件来再次启用 selection 的按钮?
2. 用户游戏结束后,游戏应在 1 秒内自动重新开始。如果我在 setbackgroundColor() 之后使用 Thread.sleep(1000),它将给我 1 秒但忽略 setBackground()。我希望用户在游戏重置前看到错误的答案(不正确的颜色背景)。

代码:

// allSquares, generatedSquares,generationSpeed can be used to change game difficulty
int allSquares = 9;
int generatedSquares = 4;
int generationSpeed = 500;
Button[] buttons = new Button[allSquares];
@IdRes
int[] ids = {R.id.b1, R.id.b2, R.id.b3, R.id.b4, R.id.b5, R.id.b6, R.id.b7, R.id.b8, R.id.b9};
Button bGenerate;
List<Integer> randomOrder;
int selectedSquare = 0;

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

    bGenerate = findViewById(R.id.bGenerate);
    bGenerate.setOnClickListener(this);
}

private void runAlgorithm()
{
    // initiate + invisible all squares
    for (int i = 0; i < allSquares; i++)
    {
        buttons[i] = findViewById(ids[i]);
        buttons[i].setAlpha(0.0f);
        buttons[i].setOnClickListener(this);
        buttons[i].setBackgroundColor(getResources().getColor(R.color.squareColor));
        buttons[i].setEnabled(false);
    }

    // generate random sequence
    randomOrder = new ArrayList<>();
    randomOrder.clear();
    Random random = new Random();
    while (randomOrder.size() < generatedSquares)
    {
        int generatedNumber = random.nextInt(allSquares);
        if (!randomOrder.contains(generatedNumber))
        {
            randomOrder.add(generatedNumber);
            Log.i("FollowThePath", generatedNumber + "");
        }
    }

    // show random sequence by order
    final int[] counter = {0};
    selectedSquare = 0;
    final Timer timer = new Timer();
    timer.schedule(new TimerTask()
    {
        @Override
        public void run()
        {
            buttons[randomOrder.get(counter[0])].setAlpha(1.0f);
            counter[0]++;
            if (counter[0] == generatedSquares)
            {
                timer.cancel();
            }
        }
    }, 0, generationSpeed);
    // Bug 1: need to enable buttons after timer finishes, user should not be allowed to choose a square during square reveal
}



@Override
public void onClick(View v)
{
    if (v.getId() == R.id.bGenerate)
        runAlgorithm();
    else
    {
        Log.i("FollowThePath", v.getTag().toString() + "       " + randomOrder.get(selectedSquare));
        if (v.getTag().toString().equals(randomOrder.get(selectedSquare).toString()))
        {
            v.setBackgroundColor(getResources().getColor(R.color.correctColor));
            v.setEnabled(false);
            selectedSquare++;
        } else
        {
            // Game Over
            Toast.makeText(this, "You failed.", Toast.LENGTH_SHORT).show();
            // Bug: setBackground executes so fast
            v.setBackgroundColor(getResources().getColor(R.color.incorrectColor));
            // Bug 2: we need a delay here, so that user sees the incorrect color and gets ready for next game
            // Thread.sleep(1000) ignores the color change, it means user can't see incorrectColor even if i add a Thread.sleep after that
            // starting a new game
            runAlgorithm();
        }
        if (selectedSquare == generatedSquares)
        {
            // Succeeded
            // Toast.makeText(this,"You did it.",Toast.LENGTH_SHORT).show();
            // run a new game
            runAlgorithm();
        }
    }
}

private void enableAllButtons(boolean enable)
{
    for (int i = 0; i < allSquares; i++)
    {
        buttons[i].setEnabled(enable);
    }
}

要解决您的第一个问题,因为 TimerTask 完成的唯一方法是根据此条件 counter[0] == generatedSquares 取消它,那么您需要做的就是这样:

@Override
public void run() {
   buttons[randomOrder.get(counter[0])].setAlpha(1.0f);
   counter[0]++;
   if (counter[0] == generatedSquares)
    {
        runOnUiThread(new Runnable()
        {
            @Override
            public void run()
            {
                enableAllButtons(true);
            }
        });
        timer.cancel();
    }
}

对于第二个问题,颜色变化可能不会出现,因为重新启动的算法启动得太快,而且所有这些都在 UI 线程上,使用 Thread.sleep(1000) 不会帮助。尝试将 runAlgorithm() 调用包装成类似以下内容:

Handler handler = new Handler();
Runnable r = new Runnable()
{
    public void run()
    {
        //what ever you do here will be done after 500 mili seconds delay.
        runAlgorithm();
    }
};
handler.postDelayed(r, 500);

希望它有效,因为我无法对其进行测试。