UI在异步后台任务

时间:2019-01-30 22:52:21

标签: java android android-asynctask

上下文

我有一个活动,用户单击击中或错过三圈,然后轮到计算机单击击中或错过。

问题

问题在于,当计算机转动程序时,该程序挂起了回收站视图,并在最终显示结果之前发出多次咔嗒声。您可以在这里看到它:

enter image description here

我尝试过的事情

通过一些故障排除,我发现我应该在后台线程中执行计算机任务,并且所有UI更改都应在runOnUiThread中执行。所以我有这个(这是onClickEvent):

AsyncTask.execute(new Runnable() {
                @Override
                public void run() {
                    playerHit(whosThrowing);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            setAdapterToDisplayStats(whosThrowing);
                            tv_numberToHit.setText(numToHit.get(whosThrowing));
                            if(amountThrownThisRound == 3 && (!opponent.equals("SINGLE"))) {
                                nextPlayerTurn(whosThrowing);
                            }
                        }
                    });
                }
            });
            break;
        case R.id.btn_miss:
            AsyncTask.execute(new Runnable() {
                @Override
                public void run() {
                    playerMissed(whosThrowing);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            setAdapterToDisplayStats(whosThrowing);
                            //Player threw their three darts. Change player.
                            if(amountThrownThisRound == 3 && (!opponent.equals("SINGLE"))) {
                                nextPlayerTurn(whosThrowing);
                            }
                        }
                    });
                }
            });
            break;

但是,这不能解决问题,上面的GIF实际上显示了此代码的结果。我首先针对Human v Human场景进行了设计,然后开始实施Human V Computer场景。我认为对于计算机而言,无论点击还是未命中,并在相关按钮上perfomClick()都可以直接得到结果。

如您在上面的代码块中看到的,大多数方法都在runOnUiThread中,这是因为这些方法包含至少一部分代码,这些代码可以更改UI,但不会干扰部分内容用户界面。我无法想象我必须遍历每行代码,然后在后台运行还是在UI线程中运行,是吗?就在电脑转弯的时候。

setAdapterToDisplayStats(whosThrowing);在单独的类中调用onBindViewHolder,该类将更新recylerview。仅setAdapterToDisplayStats(whosThrowing)是否可以确保其后的所有内容(即使它在单独的类中)都可以运行?

可能有效的代码

计算机抛出

 if(opponent.equals("COMPUTER") && confirmedPlayers.get(0).equals("A.I") && Integer.parseInt(amountThrown.get(0)) % 3  == 0){
        btn_hit.setEnabled(false);
        btn_miss.setEnabled(false);
        for (int i = 0; i < 3; i++) {
            takeCompThrow();
        }
        btn_hit.setEnabled(true);
        btn_miss.setEnabled(true);
    }
    return whosThrowing;

计算机performClick

preformClick是我最初包装在一个可运行块中的内容,认为我调用的任何内容都将在后台线程中完成。虽然这是我第一次遇到问题并将其移至onClick()的地方,但在我阅读UI时,它应该单独完成,但仍然没有乐趣。

private void takeCompThrow() {
        boolean hitOrMiss = computerThrow.computerHitOrMiss(compLevel);
        if(hitOrMiss) {
            btn_hit.performClick();
        } else {
            btn_miss.performClick();

在重要的情况下,它是如何形成Human V Human的方式:

enter image description here

主要问题

我要去哪里错了?

1 个答案:

答案 0 :(得分:1)

我认为问题与该代码块有关,因为您试图在一个非常短的时间内多次更新recyclerview。

for (int i = 0; i < 3; i++) {
  takeCompThrow();
}

由于您是计算逻辑的所有者,因此可以直接玩转牌并直接更新结果,而无需点击。在这方面,除非有巨大的计算成本,否则无需使用任何异步任务。 我的第一个建议是,您可以执行以下操作:

if this is computer turn
  for 1..3
    calculate result for the computer turn
  update recyclerview

还有第二种选择,但是我肯定会选择上面的方法。即使这将是一个快速的解决方案,但却不是最好的。您只需要在计算机单击之间设置延迟,即可让Recyclerview计算和重绘元素。因此,它将与现有代码类似:

for (int i = 0; i < 3; i++) {
  takeCompThrow();
  someDelay();
}