0

i am trying to display a Toast on the screen and when Toast fades off then move to the next question. I have tried with Thread but cannot seem to manage.

My code:

next.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (getUserSelection()){
                    position = position + 3;
                    if (position < questionsArray.size()) {
                        curName = questionsArray.get(position).getName();
                        curArray = questionsArray.get(position).getAnswers();
                        curIscorrect = questionsArray.get(position).getIscorrect();
                        setupQuestionView(curName, curArray, curIscorrect);
                    } else {
                        StringGenerator.showToast(QuestionsActivity.this, "Your score : " + score + "/" + (questionsArray.size() / 3));
                    }
                }else {
                    StringGenerator.showToast(QuestionsActivity.this, getString(R.string.noanswerselected));
                }
            }
        });

and the getUserSelectionMethod:

private boolean getUserSelection() {
        correct = (RadioButton)findViewById(group.getCheckedRadioButtonId());
        if (correct == null){
            return false;
        }else {
            correctAnswerText = correct.getText().toString();
            if (map.get(correctAnswerText).equals(Constants.CORRECTANSWER)) {
                score++;
                setCorrectMessage();
                return true;
            } else {
                setWrongMessage();
                return true;
            }
        }
    }

    private void setCorrectMessage() {
        correctToast = new Toast(QuestionsActivity.this);
        correctToastView = getLayoutInflater().inflate(R.layout.correct, (ViewGroup) findViewById(R.id.correctRootLayout));
        correctText = (TextView)correctToastView.findViewById(R.id.correctTextView);
        correctText.setText(getString(R.string.correctAnswer));
        correctToast.setDuration(Toast.LENGTH_SHORT);
        correctToast.setView(correctToastView);
        correctToast.show();
        correctThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                correctToast.cancel();
            }
        });
        correctThread.start();
    }

    private void setWrongMessage() {
        wrongToast = new Toast(QuestionsActivity.this);
        wrongToastView = getLayoutInflater().inflate(R.layout.wrong, (ViewGroup) findViewById(R.id.wrongRootLayout));
        wrongText = (TextView)wrongToastView.findViewById(R.id.wrongTextView);
        wrongText.setText(getString(R.string.wrongAnswer));
        wrongToast.setDuration(Toast.LENGTH_SHORT);
        wrongToast.setView(wrongToastView);
        wrongToast.show();
        wrongThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                wrongToast.cancel();
            }
        });
        wrongThread.start();
    }

Any suggestion on how to do this?

Kostas Drak
  • 3,222
  • 6
  • 28
  • 60

4 Answers4

2

You can determine the toast visibility:

toast.getView().getWindowToken()

If the result is null, than your toast isn't visible anymore, and than you can run any code you want.

Juvi
  • 1,078
  • 1
  • 19
  • 38
2

as stated in this answer you can start a thread that waits the duration of the Toast:

Thread thread = new Thread(){
    @Override
    public void run() {
        try {
            Thread.sleep(3500); // 3.5seconds! 
            // Do the stuff you want to be done after the Toast disappeared
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }  
};

Toast.LENGTH_SHORT and Toast.LENGTH_LONG are only flags so you have to either hard code the duration or keep them in a constant. The durations are 3.5s (long) and 2s (short).


If you want to manipulate some of your views, you cannot do this in another thread than the "main" UI thread. So you have to implement a kind of callback/polling mechanism to get notified when the SleepThread has finished. Check this answer to read about a couple of ways to do this. Probably the easiest of them to understand and implement is this:

After you started your Thread you can check if it is still alive and running by calling thread.isAlive(). In this way you can do a while loop that runs while the thread is running:

// start your thread
while(thread.isAlive()){}
// continue the work. The other thread has finished.

Please note that this is NOT the most elegant way to do this! Check the other possibilities in the answer I've mentioned above for more elegant solutions (especially the last one with the listeners is very interesting and worth reading!)

Community
  • 1
  • 1
l7r7
  • 1,134
  • 1
  • 7
  • 23
0

My Error was because i was trying to acess UI Elements through another Thread so modifying the code like this:

Thread thread = new Thread(new Runnable() {
     @Override
     public void run() {
          try {
              Thread.sleep(500);
              QuestionsActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                         moveToNextQuestion();
                    }
              });
              } catch (InterruptedException e) {
                     e.printStackTrace();
              }
     }
});
thread.start();

did the trick. I hope my answer helps someone!!!

Bhavinkumar Patel
  • 515
  • 1
  • 12
  • 28
Kostas Drak
  • 3,222
  • 6
  • 28
  • 60
0

That's because the Thread class is purely executed in the background and you need to manipulate the view in the Main thread. To solve your issue just replace the Thread with AsynTask.

AsyncTask<Void,Void,Void> a = new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                super.onPostExecute(aVoid);
                correctToast.cancel();
            }
        };
        a.execute();

If you look at my code you can see my onPostExecute, this method is called in the Main Thread.

Enzokie
  • 7,365
  • 6
  • 33
  • 39
  • @downvoters Please explain your side for downvoting my answer. It will help my post to improved and be able to give necessary facts for the future visitors. Otherwise it might give a false assumption for the issue. – Enzokie Mar 27 '16 at 13:44