10

I have a progress dialog that I use for a part in my program where I do a time intensive operation in the background but when the dialog gets displayed the UI or spinner icon freezes/slow/hesitates making the program appear as if it froze. In my onPostExecute of my AsyncTask I dismiss the dialog.

Why would this happen since I am doing all the work in the background?

here is my code

pDialog = ProgressDialog.show(FullGame.this,"Starting New Game","Please Wait...", true);
new StartNewGame().execute(); 

    private class StartNewGame extends AsyncTask<Void,Void,Boolean>{

    @Override
    protected Boolean doInBackground(Void... params) {
        try{
            ContentValues values = new ContentValues();
            Cursor c = getContentResolver().query(Games.PART1_URI,new String[] {Games.PART1_NUM},
                    Games.PART1_GAME_ID+"="+gameID+" AND "+Games.PART1_FRAME_NUM+"="+10,null,null);
            c.moveToFirst();
            String num = c.getString(0);
            int part1 =0;
            if(num.equals("-")){
                part1=0;
            }else{
                part1=Integer.parseInt(num);
            }

            c = getContentResolver().query(Games.PART2_URI,new String[] {Games.PART2_NUM},
                    Games.PART2_GAME_ID+"="+gameID+" AND "+Games.PART2_FRAME_NUM+"="+10,null,null);
            c.moveToFirst();
            int part2 = 0;
            if(num.equals("-")){
                part2=0;
            }else{
                part2=Integer.parseInt(num);
            }

            c = getContentResolver().query(Games.PART3_URI,new String[] {Games.PART3_NUM},
                    Games.PART3_GAME_ID+"="+gameID,null,null);
            c.moveToFirst();
            int part3 = 0;
            if(num.equals("-")){
                part3=0;
            }else{
                part3=Integer.parseInt(num);
            }

            if(part1 == 10){
                values.clear();
                values.put(Games.STRIKES_FRAME_NUM,10);
                values.put(Games.STRIKES_BOWLER_ID,bowlerClickedID);
                values.put(Games.STRIKES_GAME_ID,gameID);
                getContentResolver().insert(Games.STRIKES_URI, values);
            }
            if(part2 == 10){
                values.clear();
                values.put(Games.STRIKES_FRAME_NUM,10);
                values.put(Games.STRIKES_BOWLER_ID,bowlerClickedID);
                values.put(Games.STRIKES_GAME_ID,gameID);
                getContentResolver().insert(Games.STRIKES_URI, values);
            }
            if(((part2+part3) == 10) && !score.checkSpare(10)){
                values.clear();
                values.put(Games.SPARES_BOWLER_ID,bowlerClickedID);
                values.put(Games.SPARES_FRAME_NUM,10);
                values.put(Games.SPARES_GAME_ID,gameID);
                getContentResolver().insert(Games.SPARES_URI, values);
            }
            if(part3 == 10){
                values.clear();
                values.put(Games.STRIKES_FRAME_NUM,10);
                values.put(Games.STRIKES_BOWLER_ID,bowlerClickedID);
                values.put(Games.STRIKES_GAME_ID,gameID);
                getContentResolver().insert(Games.STRIKES_URI, values);
            }
        c.close();
        }catch(Exception e){
            Log.d("FullGame",e.toString());
        }

        Date date = new Date(System.currentTimeMillis());
        DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
        String newDate = df.format(date);

        ContentValues values = new ContentValues();
        values.put(Games.GAMES_BOWLER_ID,bowlerClickedID);
        values.put(Games.GAMES_TEAM_ID,1);
        values.put(Games.GAMES_DATE,newDate);
        values.put(Games.GAME_SEASON, pref.getLong(Preferences.SELECTED_SEASON, 1));
        values.put(Games.GAMES_TOURNAMENT_ID, tournamentID);
        Uri uri = getContentResolver().insert(Games.GAMES_URI, values);
        gameID = ContentUris.parseId(uri);
        int gameid = Integer.valueOf(String.valueOf(gameID));
        values.clear();
        Cursor cName = getContentResolver().query(BowlersDB.CONTENT_URI,new String[] {BowlersDB.FIRST_NAME},BowlersDB.ID+"="+bowlerClickedID,null,null);
        cName.moveToFirst();
        String name = cName.getString(0);
        for(int i = 0;i<10;i++){
            int num = i+1;
            values.put(Games.NAMES_FRAME_NUM,num);
            values.put(Games.NAMES_GAME_ID,gameid);
            values.put(Games.NAMES_NAME,name);
            getContentResolver().insert(Games.NAMES_URI, values);
            names(i,name);
            values.clear();
            values.put(Games.PART1_FRAME_NUM,num);
            values.put(Games.PART1_NUM,"0");
            values.put(Games.PART1_GAME_ID,gameid);
            getContentResolver().insert(Games.PART1_URI, values);
            values.clear();
            values.put(Games.PART2_FRAME_NUM,num);
            values.put(Games.PART2_NUM,"0");
            values.put(Games.PART2_GAME_ID,gameid);
            getContentResolver().insert(Games.PART2_URI, values);
            values.clear();
            values.put(Games.TOTALS_FRAME_NUM,num);
            values.put(Games.TOTALS_FRAME_TOTAL,"0");
            values.put(Games.TOTALS_GAME_ID,gameid);
            getContentResolver().insert(Games.TOTALS_URI, values);
            values.clear();
            values.put(Games.POCKETS_BOWLER_ID,bowlerClickedID);
            values.put(Games.POCKETS_FRAME_NUM,i);
            values.put(Games.POCKETS_GAME_ID,gameID);
            values.put(Games.POCKETS_TEAM_ID, teamSelectedID);
            values.put(Games.POCKETS_TOURNAMENT_ID, tournamentID);
            values.put(Games.POCKETS_NUM, 0);
            values.put(Games.POCKETS_SEASON, pref.getLong(Preferences.SELECTED_SEASON, 1));
            getContentResolver().insert(Games.POCKETS_URI, values);
            values.clear();
        }

        values.put(Games.PART3_GAME_ID,gameid);
        values.put(Games.PART3_NUM,"0");
        getContentResolver().insert(Games.PART3_URI, values);
        cName.close();
        part1Array = new int[10];
        part2Array = new int[10];
        totalsArray = new int[10];
        part3 = 0;
        mPinsUp = new ArrayList<Long>();
        mPinsUp.add((long) 1);
        mPinsUp.add((long) 2);
        mPinsUp.add((long) 3);
        mPinsUp.add((long) 4);
        mPinsUp.add((long) 5);
        mPinsUp.add((long) 6);
        mPinsUp.add((long) 7);
        mPinsUp.add((long) 8);
        mPinsUp.add((long) 9);
        mPinsUp.add((long) 10);
        return true;
    }

    protected void onPostExecute(Boolean result){
            pDialog.dismiss();
    }

}

UPDATE: running through the code in debug mode last night it seems to start to do it in the for loop but still all of this is done in a separate thread and I am only inserting values into my database

UPDATE 2 if I comment out the for loop the progress dialog gets displayed for less than a second so even though I am doing everything in an AsyncTask the inserts must still run in the UI thread

tyczj
  • 71,600
  • 54
  • 194
  • 296
  • Are you doing this on the main thread or the ui thread. There are other topics about this on SO, maybe they will help. http://stackoverflow.com/questions/3652560/what-is-the-android-uithread-ui-thread – Rod Burns Aug 13 '12 at 13:12
  • well as you can see it is an AsyncTask so it would be in another thread – tyczj Aug 13 '12 at 14:50
  • where is your `onPreExecute` section? Also you can put all the code in `doInBackground` into a method as it should all execute in the new thread anyway, and make all this easier to read. Also what hardware are you testing on? – Graham Smith Aug 13 '12 at 15:00
  • I don't have a `onPreExecude` method is it even needed?. I tested this on Galaxy Nexus, Nexus 7 and Samsung Galaxy Tab 10.1 all with the same results – tyczj Aug 13 '12 at 17:14
  • I also had a problem like this, due to my UI thread being blocked. I'd suggest you have a look if you are possibly blocking it somewhere in your code. – Luke Taylor Aug 13 '12 at 17:21
  • @Luke this is all done on a button click after everything has been loaded so basically the program is sitting idle at this time – tyczj Aug 13 '12 at 17:24
  • 1
    perhaps this question and its answers will help you [link](http://stackoverflow.com/questions/11604914/contentprovider-insert-always-runs-on-ui-thread) – SteveR Aug 14 '12 at 02:22

5 Answers5

2

This probably happens because your background thread consumes 100% of device CPU. When CPU is busy processing one thread, UI thread won't be updated and therefore you see it as frozen

Try to detect what's the most aggressive operation by removing parts of code from your doInBackground and running the app again. Also try to see how it performs when device is not plugged via USB - this some times provides weird results

Anton
  • 4,395
  • 7
  • 32
  • 46
  • the problem is in the for loop where it is inserting fields into my database. If i comment that out it shows the progress dialog for less than a second so apparently even though I am doing everything in an `AsyncTask` the inserts must still be running in the UI thread – tyczj Aug 16 '12 at 22:51
2

Figured it out, I had a runaway method going on the UI thread that i did not notice

tyczj
  • 71,600
  • 54
  • 194
  • 296
0

You are using the ProgressDialog wrong.

You need to add a onPreExecute method, and there you define and show your ProgressDialog. Then doInBackground is performed on another thread, and eventually in onPostExecute you dismiss the dialog.

Here's a simple example:

class RefreshChanges extends AsyncTask<String, Void, String> {
        private ProgressDialog mProgressDialog = new ProgressDialog(
                mContext);

        @Override
        protected void onPreExecute() {
            mProgressDialog.setTitle("Whatever title");
            mProgressDialog.setMessage("Whatever message");
            mProgressDialog.show();
        }

        protected String doInBackground(String... strings) {
            // Do whatever processing you want...
            return "";
        }

        protected void onPostExecute(String result) {
            mProgressDialog.dismiss();
            mProgressDialog = null;
        }
    }
    new RefreshChanges().execute();

By the way, I also recommend you not to use hardcoded strings. Instead, you can go to the strings.xml file under res\values\ and define a string. Then in your code, you can use either getString(R.string.yourStringId) or R.string.yourStringId. It depends whether the method accepts Id's or not (Methods that accept Id's, actually perform getString with the Id you sent it).

RE6
  • 2,684
  • 4
  • 31
  • 57
  • But what is the difference if I use `onPostExecute` or just declare the progress dialog right before i start the AsyncTask? I just dont see how that would fix the problem since both are in the UI thread correct? – tyczj Aug 14 '12 at 17:16
  • @tyczj I honestly don't know the exact difference (but by saying this, you are rising the question why `onPostExecute` is needed at all). It seems there is a difference, because I had the same problem you are experiencing. I also defined the `ProgressDialog` out of the AsyncTask, and when I moved inside, it worked perfectly smoothly. I suggest you try it and see. It should work – RE6 Aug 14 '12 at 17:37
  • I threw it in the onPreExecute and it still did the same thing unfortunately – tyczj Aug 14 '12 at 22:02
0

I have implemented the dialog this way with success.

private ProgressDialog progress;

private class AsynTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected void onPreExecute() {
           progress = ProgressDialog.show(context, "", "Please wait...", true);

       }

        @Override
        protected void onPostExecute(Void params) {
             if (progress.isShowing()) 
                  progress.dismiss();

       }

        @Override
        protected Void doInBackground(Void... arg0) {
             // Do some work
             return null;
       }
 }
Mike Mackintosh
  • 13,917
  • 6
  • 60
  • 87
CAM-Dev
  • 186
  • 3
0

i don't see any fault in your code, but you have to understand that only writing code in another thread does not means it will get another processor. if your device is having single core processor it does time slicing and does work in round robin way. if your device has multiple cores it will do actual multiple threading. so if you have single core processor it will show you some lag in progress bar.

user1503346
  • 91
  • 1
  • 5