1

I am writing a board game in Android where the UI consists of textViews for the scores (CPUScore and PlayerScore). The problem I have is that the UI does not update the score from its initial value when onCreate is called. I have looked at similar questions and the solution most suggested is to use AsyncTask to update the UI thread in the background. However I did not find a solution that dealt explicitly with how to use textViews in AsyncTask.

Here is my attempt:

@Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
//....
setContentView(R.layout.main_layout);

//.....
//------------ textViews declared here don't refresh -------------------
TextView playerScoreForm = (TextView) findViewById(R.id.PlayerTotalScore);
        playerScoreForm.setText(Integer.toString(PlayerTotal));
        playerScoreForm.invalidate();

        TextView CPUScoreForm = (TextView) findViewById(R.id.CPUTotalScore);
        CPUScoreForm.setText(Integer.toString(CPUTotal));
        CPUScoreForm.invalidate();
//--------------------------------------------------------------------------    
//AsyncTask method:    
        new updatePlayerScore().execute(PlayerTotal);
        new updateCPUScore().execute(CPUScoreForm);
    }

The AsyncTask subclasses:

private class updatePlayerScore extends AsyncTask<TextView, Void, Void> {

        @Override
            protected TextView doInBackground(TextView... params) {


                    // what to put here??



            }
             return playerScoreForm;
         }

            @Override
         protected void onProgressUpdate(Integer... values) {
             //??
         }

         protected void onPostExecute(Integer result) {
            playerScoreForm.setText(Integer.toString(result));
         }

     }


    private class UpdateCPUScore extends AsyncTask<TextView, Integer, Integer> {
        // same syntax as updatePlayerScore

     }

Question: how do I transfer the textViews that I declared in the onCreate method to the AsyncTask method? I am stumped. I am fairly new to Android development.

Buzz
  • 516
  • 7
  • 21
  • make `playerScoreForm` and so on class members / pass them in the constructor or the params of your custom AsyncTask. – zapl Apr 02 '12 at 22:53
  • Could you please give me a rough example of how to do that? – Buzz Apr 02 '12 at 23:25

2 Answers2

2

a) I'm pretty sure you shouldn't need to invalidate the TextViews after you set them; Android should do that automagically.

b) In theory you'd set your TextView references to be member variables and then reference them in onPostExecute instead of passing them into doInBackground. doInBackground in turn will take whichever bits of data enable you to calculate the new score. What you would do on doInBackground is whatever action would cause a new score to be calculated. The return value from doInBackground gets passed into onPostExecute. You would then update the TextView (now a member variable) with this data in onPostExecute. Does that make sense? You haven't actually posted any code here that would update those score values.

See here for a quick example.

private TextView myScoreView;  //initialized in onCreate as you do above.


@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    //....
    setContentView(R.layout.main_layout);

    //.....

    myScoreView = (TextView) findViewById(R.id.PlayerTotalScore);
    myScoreView.setText(Integer.toString(PlayerTotal));

    new updatePlayerScore().execute(1,2); //parameters for calculation
}

private class updatePlayerScore extends AsyncTask<Integer, Integer, Integer> {

        @Override
        protected TextView doInBackground(Integer... params) {

                int score = params[0] + 2 * params[1];
                return score;
        }


        @Override
        protected void onProgressUpdate(Integer... values) {
            //if you want to provide some indication in the UI that calculation 
            //is happening, like moving a progress bar, that's what you'd do here.
        }

        @Override
        protected void onPostExecute(Integer scoreCalculationResult) {
           myScoreView.setText(Integer.toString(scoreCalculationResult));
        }

 }

Edit: If you don't want to do the calculation logic in doInBackgroundThread, you probably just want to use:

runOnUiThread(new Runnable(){
     @Override
     public void run(){
         myScoreView.setText(PlayerScoreValue);
     }
});

Or:

 myScoreView.post(new Runnable(){
     @Override
     public void run(){
         myScoreView.setText(PlayerScoreValue);
     }
});
Jon O
  • 6,532
  • 1
  • 46
  • 57
  • Thanks for your comment. The scores public int PlayerTotal and public int CPUTotal are updated by the game logic during game play. My question is how to convert: TextView playerScoreForm = (TextView) findViewById(R.id.PlayerTotalScore); playerScoreForm.setText(Integer.toString(PlayerTotal)); to an AsyncTask process. When setText is performed on the textView PlayerScoreForm the updated value of PlayerTotal (updated from game loop) is not passed on to the UI thread. – Buzz Apr 02 '12 at 23:20
  • It sounds like AsyncTask is not the right thing to use here, then. I'll update my answer. – Jon O Apr 03 '12 at 00:18
  • Thanks a lot. I used your first edit suggestion and enclosed it in a void method updateScores(): public void updateScores() { runOnUiThread(new Runnable() { @Override public void run() { playerScoreForm.setText(Integer.toString(PlayerTotal)); CPUScoreForm.setText(Integer.toString(CPUTotal)); } }); }. The trick was to call it from onCreate for the initial score then call it from the method in the game where the scores are generated. – Buzz Apr 03 '12 at 19:13
0

You can pass the TextView in the constructor of the AsyncTask and update it from the onPostExecute method

private class updatePlayerScore extends AsyncTask<Void, Void, Integer> {
private TextView view;
public updatePlayerScore(TextView textView){
this.view = textView;
}
        @Override
            protected Integer doInBackground(Void... params) {
            int score = 0; 

                    //do you calculation the 

             return score;
         }
         protected void onPostExecute(Integer result) {
           view.setText(Integer.toString(result));
         }

     }

note: if you Activity configuration change for any reason i.e the user rotate the device and the you AsyncTask hasn't finish it task the update of you TextView will not be updated so you should retain an instance of you AsyncTask and update the the TextView

confucius
  • 13,127
  • 10
  • 47
  • 66
  • Thanks for your contribution. My mistake was that I was trying to get scores from onCreate but this was wrong because onCreate will only fire once (i.e when the activity is first created) so trying to get scores there when onCreate has been executed meant that the scores retained their initial values which were passed to onCreate at initialisation. – Buzz Apr 03 '12 at 19:17