0

I am making an AI version of game 2048. After the game tree is created in background, I want to update the UI with asynctask. It doesn't work for now. This is where I use the AsyncTask in MainActivity.java;

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) {

    }
}

Calling it from onCreate();

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

With publishProggress(path), I am sending the list path which has the moves that the AI will do. But when it comes to the onProggressUpdate() and execute the onSwipeLeft() for example, it does not update the game screen. Am I using AsyncTask correctly? Thank you for your help.

UPDATE: It is now updating the UI but doesn't wait for the publishProggress() to finish. How do I do that?

elif erdil
  • 39
  • 7
  • what onSwipeLeft is doing? I guess the problem is there! – Wasi Ahmad Nov 25 '16 at 18:11
  • It moves the tiles to the left. It is working normally, when AI is not activated. @WasiAhmad – elif erdil Nov 25 '16 at 18:48
  • so, you believe the problem is probably in AI logic?? then you can debug to see, what your AI logic is doing in particular situations! i don't see any problem in the code you provided. – Wasi Ahmad Nov 25 '16 at 19:35
  • I believe the problem is in `AsyncTask`. I've never used it before, maybe there is something wrong with it. I think AI logic is correct, debugged but couldn't find the problem. There are two `publishProgress()` method in `doInBackground()`, is it right way to use? @WasiAhmad – elif erdil Nov 25 '16 at 20:06
  • Yes, its fine. According to me you are doing just one thing wrong, i am not sure whether that is the reason or not! I have mentioned that in my answer. – Wasi Ahmad Nov 25 '16 at 20:35

1 Answers1

1

I don't know why you have commented out the statement: super.onProgressUpdate(path); inside your onProgressUpdate method. You shouldn't do that.

Since you are using asynctask for the first time, i am giving you a very simple example that updates UI components (textview and a progressbar) from asynctask.

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

    }
}

Hopefully it will help you. You can find complete working examples in web. See them for comprehensive understanding about asynctask.

UPDATE: For achieving synchronization in between doInBackground() and publishProgress(), you can use synchronization block on some global object or you can use a simple flag to hold executation of doInBackground() which is called busy waiting.

Synchronized Block:

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

Busy Waiting: (not preferred way)

use a flag _publishFinished = false; then call publish progress. Do busy waiting in doInBackground() as follows.

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

at end of onProgressUpdate call

_publisFinish = true;
Wasi Ahmad
  • 35,739
  • 32
  • 114
  • 161
  • Thank you for your effort, but my problem is that; `UI` is updated after the second `publishProggress()` method in `while` is executed. I want it to execute after the first `publishProggress()` is executed. They are not waiting each other i guess. – elif erdil Nov 26 '16 at 13:32
  • @eliferdil its not working yet? which publishProgress() is not working!! I believe you can do some trick to handle any special scenario if required :) – Wasi Ahmad Nov 26 '16 at 22:35
  • There is an asynchronization. Before `publishProggress()` finishes its job, `doItBackground()` continues and wrong values go. I guess this is how it is supposed to be when using `AsyncTask`. But i need them to be synchronzed. How do I synchronize them? @WasiAhmad – elif erdil Nov 27 '16 at 16:44
  • @eliferdil i guess this is what you are looking for - http://stackoverflow.com/questions/9893813/can-an-android-asynctask-doinbackground-be-synchronized-to-serialize-the-task-ex – Wasi Ahmad Nov 27 '16 at 17:42
  • This is for usage of more than one `AsyncTask`. In my case, the asynchronization is between `doInBackground()` and `publishProggress()`. @WasiAhmad – elif erdil Nov 27 '16 at 18:15
  • @eliferdil what you need is to use synchronize block to hold doInBackground while executing publishProgress(). see this post - http://stackoverflow.com/questions/19173569/wait-publishprogress-finish-before-continue-excute-doinbackground-asynctask-andr – Wasi Ahmad Nov 27 '16 at 20:22
  • @eliferdil is your problem solved? did you get any help from my updated answer? – Wasi Ahmad Dec 03 '16 at 02:45