【问题标题】:Can't update the UI with AsynckTask on Android无法在 Android 上使用 AsynckTask 更新 UI
【发布时间】:2016-11-25 17:32:12
【问题描述】:

我正在制作游戏2048的AI版本。在后台创建游戏树后,我想用asynctask更新UI。它现在不起作用。 这是我在MainActivity.java; 中使用AsyncTask 的地方

private class AsyncTaskRunner extends AsyncTask<Void, String, Void> {

    @Override
    protected Void doInBackground(Void... v) {
        try {
            Tree tree = new Tree(gameEngine);
            List<Node> path;

            Node root = new Node(gameEngine.grid.cells);

            tree.createInitialTree(root);
            path = ai.findPath(root);
            Node maxNode = path.get(path.size() - 1);

            for (Node node : path) {
                SystemClock.sleep(500);
                publishProgress(node.getDir());
            }

            while (!maxNode.myLose && (gameEngine.grid.areCellsAvailable(maxNode.getBoard()) || gameEngine.availableTileMatchLeft(maxNode)
                    || gameEngine.availableTileMatchRight(maxNode) || gameEngine.availableTileMatchUp(maxNode) ||
                    gameEngine.availableTileMatchDown(maxNode))) {
                tree = new Tree(gameEngine);
                tree.createTree(maxNode);

                path = ai.findPath(maxNode);

                for (Node node : path) {
                    SystemClock.sleep(500);
                    publishProgress(node.getDir());
                }

                maxNode = path.get(path.size() - 1);

            }
            System .out.println("You lose!!!");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void onProgressUpdate(String... direction) {
        switch (direction[0]) {
            case "left": onLeftSwipe();
                break;
            case "right": onRightSwipe();
                break;
            case "down": onDownSwipe();
                break;
            case "up": onUpSwipe();
                break;
        }
        super.onProgressUpdate(direction);
    }

    @Override
    protected void onPostExecute(Void v) {

    }
}

onCreate()调用它;

    AsyncTaskRunner runner = new AsyncTaskRunner();
    runner.execute();

使用publishProggress(path),我将发送列表path,其中包含人工智能将执行的动作。但是当涉及到onProggressUpdate() 并执行onSwipeLeft() 时,它不会更新游戏画面。我是否正确使用AsyncTask?感谢您的帮助。

更新:它现在正在更新UI,但不会等待publishProggress() 完成。我该怎么做?

【问题讨论】:

  • onSwipeLeft 在做什么?我想问题就在那里!
  • 它将图块向左移动。当AI未激活时,它正常工作。 @WasiAhmad
  • 那么,您认为问题可能出在 AI 逻辑上??然后您可以调试以查看您的 AI 逻辑在特定情况下正在做什么!我在您提供的代码中没有发现任何问题。
  • 我相信问题出在AsyncTask。以前没用过,可能有问题。我认为 AI 逻辑是正确的,经过调试但找不到问题。 doInBackground()中有两个publishProgress()方法,使用方法对吗? @WasiAhmad
  • 是的,没问题。根据我的说法,您只做错了一件事,我不确定这是否是原因!我在回答中提到了这一点。

标签: android-asynctask artificial-intelligence


【解决方案1】:

我不知道您为什么在 onProgressUpdate 方法中注释掉了以下声明:super.onProgressUpdate(path);。你不应该那样做。

由于您是第一次使用asynctask,我给您一个非常简单的示例,它从asynctask 更新UI 组件(文本视图和进度条)。

public class MainActivity extends ActionBarActivity {
    ProgressBar progressBar;
    TextView textOut1, textOut2, textOut3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // required codes goes here
    }

    public class MyAsyncTask extends AsyncTask<Void, Integer, Void>{

        @Override
        protected void onPreExecute() {
            //In UI thread, you can access UI here
            super.onPreExecute();
            String s1 = textIn1.getText().toString();
            textOut1.setText(s1);
        }

        @Override
        protected Void doInBackground(Void... arg0) {

            for(int i=0; i<=10; i++){
                SystemClock.sleep(1000);
                publishProgress(i);  //update UI in onProgressUpdate

                //Can GET from UI elements
                String s2 = textIn2.getText().toString();

                final String msgInBackGround = "doInBackground: " + i + " - " + s2;

                /*
                * Cannot direct SET UI elements in background thread
                * so do with runOnUiThread()
                */
                runOnUiThread(new Runnable(){
                    @Override
                    public void run() {
                    textOut2.setText(msgInBackGround);
                }});
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            //In UI thread, you can access UI here
            textOut3.setText("onPostExecute");
            super.onPostExecute(result);
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            //In UI thread, you can access UI here
            progressBar.setProgress(values[0]);
            super.onProgressUpdate(values);
        }

    }
}

希望对您有所帮助。您可以在 web.xml 中找到完整的工作示例。查看他们以全面了解asynctask

更新:为了在doInBackground()publishProgress() 之间实现同步,您可以在某个全局对象上使用同步块,或者您可以使用一个简单的标志来保持doInBackground() 的执行,即叫忙等待。

同步块

protected List<Data> doInBackground(String... params) {

    synchronize(data) // data is some global object
    {
        // do some job 1
        publishProgress(); // wait until the progress finish
        //do some job 3
    }
}

protected void onProgressUpdate(Void... values) {
    synchronize(data) // data is the same global object
    {
        // do some job
    }
}

忙着等待:(不是首选方式

使用标志_publishFinished = false; 然后调用发布进度。请在doInBackground() 中等待如下。

if(!_publishFinish){
   Thread.Sleep(200); // busy waiting
}

onProgressUpdate 调用结束时

_publisFinish = true;

【讨论】:

  • 感谢您的努力,但我的问题是; UIwhile 中的第二个publishProggress() 方法执行后更新。我希望它在第一个 publishProggress() 被执行后执行。我猜他们不会互相等待。
  • @eliferdil 还不行吗?哪个 publishProgress() 不起作用!如果需要,我相信您可以采取一些技巧来处理任何特殊情况:)
  • 存在异步。在publishProggress() 完成它的工作之前,doItBackground() 继续并且错误的值出现。我想这就是使用AsyncTask 时的样子。但我需要它们同步。如何同步它们? @WasiAhmad
  • @eliferdil 我想这就是你要找的东西 - stackoverflow.com/questions/9893813/…
  • 这用于多个AsyncTask。就我而言,异步在doInBackground()publishProggress() 之间。 @WasiAhmad
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-05
  • 2013-11-13
  • 1970-01-01
  • 2014-02-16
相关资源
最近更新 更多