Я создаю викторину. Я хочу, чтобы правильная / неправильная анимация появлялась сразу после того, как пользователь нажимает ответ, а затем через 3 секунды вопрос автоматически переключался (переходя к следующему вопросу). Я пробовал сделать это с помощью Thread.sleep (3000), но вся программа зависает. Это мой код на данный момент:

binding.buttonTrue.setOnClickListener(view -> {
            checkAnswer(true);
            updateQuestion();
            //these two calls invoke right/wrong animation

            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            changeTheQuestion();
            //this invokes fade animation

        });

Как я могу добавить промежуток времени между этими двумя анимациями? Спасибо!

Полный код: пакет com.bawp.trivia;

import android.graphics.Color;
import android.media.AudioAttributes;
import android.media.SoundPool;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;

import com.bawp.trivia.data.Repository;
import com.bawp.trivia.databinding.ActivityMainBinding;
import com.bawp.trivia.model.Question;
import com.google.android.material.snackbar.Snackbar;

import java.util.ArrayList;
import java.util.List;

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;

public class MainActivity extends AppCompatActivity {

    List<Question> questionList;
    Handler mHandler;
    private ActivityMainBinding binding;
    private int currentQuestionIndex = 0;
    SoundPool soundPool;
    private int sound1, sound2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        questionList = new Repository().getQuestions(questionArrayList -> {
                    binding.questionTextview.setText(questionArrayList.get(currentQuestionIndex)
                            .getAnswer());

                    updateCounter(questionArrayList);
                }

        );

        mHandler = new Handler();


        binding.buttonNext.setOnClickListener(view -> {

            currentQuestionIndex = (currentQuestionIndex + 1) % questionList.size();
            updateQuestion();

        });


        binding.buttonTrue.setOnClickListener(view -> {

          checkAnswer(true);
          updateQuestion();

          new Handler().postDelayed(new Runnable() {
              @Override
              public void run() {
                  changeTheQuestion();
              }
          }, 3000);

        });




        binding.buttonFalse.setOnClickListener(view -> {

            checkAnswer(true);
            updateQuestion();

            new Handler().postDelayed(new Runnable() {
                public void run() {
                    changeTheQuestion();
                }
            }, 3000);



        });



        AudioAttributes audioAttributes = new AudioAttributes.Builder()
                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
                .build();

        soundPool = new SoundPool.Builder()
                .setMaxStreams(4)
                .setAudioAttributes(audioAttributes)
                .build();

        sound1 = soundPool.load(this, R.raw.correct, 1);
        sound2 =  soundPool.load(this, R.raw.wrong, 1);


    }

    private void checkAnswer(boolean userChoseCorrect) {
        boolean answer = questionList.get(currentQuestionIndex).isAnswerTrue();
        int snackMessageId = 0;
        if (userChoseCorrect == answer) {
            snackMessageId = R.string.correct_answer;
            fadeAnimation();
            soundPool.play(sound1, 1, 1, 0, 0, 1);
        } else {
            snackMessageId = R.string.incorrect;
            shakeAnimation();
            soundPool.play(sound2, 1, 1, 0, 0, 1);
        }
        Snackbar.make(binding.cardView, snackMessageId, Snackbar.LENGTH_SHORT)
                .show();

    }

    private void updateCounter(ArrayList<Question> questionArrayList) {
        binding.textViewOutOf.setText(String.format(getString(R.string.text_formatted),
                currentQuestionIndex, questionArrayList.size()));
    }

    private void fadeAnimation() {
        AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.0f);
        alphaAnimation.setDuration(300);
        alphaAnimation.setRepeatCount(1);
        alphaAnimation.setRepeatMode(Animation.REVERSE);


        binding.cardView.setAnimation(alphaAnimation);

        alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                binding.questionTextview.setTextColor(Color.GREEN);
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                binding.questionTextview.setTextColor(Color.WHITE);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });





    }
    private void changeTheQuestion() {
        AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.0f);
        alphaAnimation.setDuration(300);
        alphaAnimation.setRepeatCount(1);
        alphaAnimation.setRepeatMode(Animation.REVERSE);




        binding.cardView.setAnimation(alphaAnimation);

        alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                binding.questionTextview.setTextColor(Color.BLUE);
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                currentQuestionIndex = (currentQuestionIndex + 1) % questionList.size();
                updateQuestion();
                binding.questionTextview.setTextColor(Color.WHITE);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });





    }

    private void updateQuestion() {
        String question = questionList.get(currentQuestionIndex).getAnswer();
        binding.questionTextview.setText(question);
        updateCounter((ArrayList<Question>) questionList);
    }

    private void shakeAnimation() {
        Animation shake = AnimationUtils.loadAnimation(MainActivity.this,
                R.anim.shake_animation);
        binding.cardView.setAnimation(shake);


        shake.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                binding.questionTextview.setTextColor(Color.RED);

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                binding.questionTextview.setTextColor(Color.WHITE);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });






    }

    


}
2
CodingChap 2 Май 2021 в 22:49

2 ответа

Лучший ответ

Вы не можете вызвать Thread.sleep() в основном (UI) потоке. Это приведет к зависанию вашего приложения и его сбою с ошибкой ANR (приложение не отвечает).

Вы можете просто опубликовать Runnable, который запустит фрагмент кода через определенный период времени. Что-то вроде этого:

new Handler().postDelayed(new Runnable() {
    public void run() {
        changeTheQuestion();
    }
}, 3000);
2
David Wasser 2 Май 2021 в 20:26

Один из способов - запустить поток, а затем засыпать этот поток на x секунд, а затем заставить его изменить вопрос. Я думаю, что с AsyncTask в java должно быть легко ... Тем более, что у него есть onPostExecute (или как он называется) функция ..

class WaitTask extends AsyncTask<Void, Void, Void> {
 protected Void doInBackground(....) {
     //Do the sleep
 }

 protected void onPostExecute(Void result) {
     // Change the question.. 
 }
}

Приведенный выше код точно не тестировался! (записано по телефону) Но, может быть, подскажет ... Также не забудьте начать ветку!

Еще лучше, вероятно, было бы использовать объект таймера, как описано здесь: Как установить таймер в android?

-1
Payerl 2 Май 2021 в 20:32