Обработчик все еще работает, хотя срок действия CountDownTimer истекает - PullRequest
0 голосов
/ 18 января 2020

Я создал обработчик, чтобы показать разные изображения игральных костей во время работы моего запуска. Обычно, когда я нажимаю кнопку «Бросить», мой таймер начинает отсчет с 3, и приложение показывает значение кости. Но иногда изображения продолжают меняться, хотя время таймера истекает.

Я думаю, что мой runnable все еще работает в фоновом режиме. Итак, как же я могу полностью остановить свой обработчик, когда истечет время?

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 приложения: https://github.com/basarballioz/Dice-Rollerdroid

1 Ответ

1 голос
/ 18 января 2020

Эта строка

new CountDownTimer(3000, 1000) 

создает таймер обратного отсчета, который запускает onTick по истечении 1 секунды, по истечении 2 секунд и, возможно, по истечении 3 секунд (не актуально, но стоит проверить).

На каждом из вызовов onTick (2 или 3 вызова) вы создаете новый обработчик и назначаете его:

handler = new Handler();

и post it. Каждый раз, когда завершается каждый обработчик (сейчас 2 или 3 обработчика), они перепланируются на 100 миллисекунд спустя:

handler.postDelayed(runnable, 100);

Обратите внимание, что запускаемый экземпляр также воссоздается, что не нужно.

Когда onFinish вызывается (после 2 или 3 тактов) - 2 или 3 обработчика работают и повторяются каждые 100 миллисекунд.

Только последний обработчик или (2-й или 3-й) отменяется onFinish и начальным Обработчики 1 или 2 продолжают работать.

Изображение ...

enter image description here

Вам определенно не нужно больше одного обработчика и запускаемый экземпляр - фактически, вам вообще не нужен обработчик, поскольку CountDownTimer по сути уже делает это. Используете ли вы CountDownTimer или просто Handler со счетчиком, зависит от вас.

Если вы хотите, чтобы лицо в кости (показанное значение) менялось каждые 100 миллисекунд в течение 3 секунд после задержки в 1 секунду, затем измените onTick, чтобы запускать обработчик только один раз (или вообще удалите обработчик - см. предлагаемый код). (Обратите внимание, что в настоящее время реализация начинает менять кости после начальной 1 секунды.)

(Вероятно, вам необходимо указать в сообщении, что вы действительно хотите, чтобы произошло.)

Ссылочная библиотека неправильно реализована.

Я бы предложил более простой подход, который устраняет избыточность кода 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);
...