【问题标题】:Wait for thread to finish and then move to next position等待线程完成然后移动到下一个位置
【发布时间】:2016-07-14 20:12:58
【问题描述】:

我正在尝试在屏幕上显示Toast,当Toast 消失时,然后转到下一个问题。我尝试过使用Thread,但似乎无法管理。

我的代码:

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));
                }
            }
        });

和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();
    }

关于如何做到这一点的任何建议?

【问题讨论】:

  • 它给了我这个错误:只有创建视图层次结构的原始线程才能触摸它的视图

标签: android multithreading android-toast


【解决方案1】:

您可以确定 toast 的可见性:

toast.getView().getWindowToken()

如果结果为 null,则您的 toast 将不再可见,您可以运行任何您想要的代码。

【讨论】:

    【解决方案2】:

    this answer 中所述,您可以启动一个等待 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_SHORTToast.LENGTH_LONG 只是标志,因此您必须对持续时间进行硬编码或将它们保持为常数。持续时间为 3.5s(长)和 2s(短)。


    如果您想操作某些视图,则不能在“主”UI 线程之外的另一个线程中执行此操作。所以你必须实现一种回调/轮询机制,以便在SleepThread 完成时得到通知。 检查this answer 了解几种方法。其中最容易理解和实现的可能是这样的:

    启动线程后,您可以通过调用thread.isAlive() 来检查它是否仍处于活动状态并正在运行。这样你就可以在线程运行时做一个while循环:

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

    请注意,这不是最优雅的方式!检查我上面提到的答案中的其他可能性以获得更优雅的解决方案(尤其是与听众的最后一个非常有趣且值得一读!)

    【讨论】:

    • 它给了我这个错误:只有创建视图层次结构的原始线程才能触摸它的视图
    • sleep 之后你在做什么?您是否操纵任何视图?
    • @helldawg13 我更新了我的答案。也许这对你有帮助。我也注意到你在下面的回答。这也很好。
    【解决方案3】:

    那是因为Thread 类纯粹在后台执行,您需要在主线程中操作视图。要解决您的问题,只需将 Thread 替换为 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();
    

    如果你看我的代码你可以看到我的onPostExecute,这个方法是在主线程中调用的。

    【讨论】:

    • @downvoters 请解释你对我的回答投反对票的立场。这将有助于我的帖子改进,并能够为未来的访问者提供必要的事实。否则,它可能会对该问题做出错误的假设。
    【解决方案4】:

    我的错误是因为我试图通过另一个线程访问 UI 元素,所以修改如下代码:

    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();
    

    成功了。希望我的回答对大家有所帮助!!!

    【讨论】:

      猜你喜欢
      • 2018-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-18
      • 2020-04-14
      相关资源
      最近更新 更多