28

I am trying to display a progress dialog during the onCreate() method of one of my activities, have the work done to populate the screen done in a thread, and then dismiss the progress dialog.

Here is my onCreateMethod()

dialog = new ProgressDialog(HeadlineBoard.this);
        dialog.setMessage("Populating Headlines.....");
        dialog.show();
        populateTable();

The populateTable method contains my thread and the code to dismiss the dialog, but for some reason. The activity comes up blank for about 10 secs(doing the populateTable() work), and then I see the screen. I never see the dialog displayed, any ideas?

Here is the populateTable() code:

//Adds a row to the table for each headline passed in
private void populateTable() {
    new Thread() {
        @Override
        public void run() {
            //If there are stories, add them to the table
            for (Parcelable currentHeadline : allHeadlines) {
                addHeadlineToTable(currentHeadline);
            }
               try {
                     // code runs in a thread
                     runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                dialog.dismiss();
                            }
                     });
               } catch (final Exception ex) {
                   Log.i("---","Exception in thread");
               }
        }
 }.start();

}
user1154644
  • 4,491
  • 16
  • 59
  • 102

3 Answers3

31

If you already have the data "for (Parcelable currentHeadline : allHeadlines)," then why are you doing that in a separate thread?

You should poll the data in a separate thread, and when it's finished gathering it, then call your populateTables method on the UI thread:

private void populateTable() {
    runOnUiThread(new Runnable(){
        public void run() {
            //If there are stories, add them to the table
            for (Parcelable currentHeadline : allHeadlines) {
                addHeadlineToTable(currentHeadline);
            }
            try {
                dialog.dismiss();
            } catch (final Exception ex) {
                Log.i("---","Exception in thread");
            }
        }
    });
}
Michael
  • 3,982
  • 4
  • 30
  • 46
Cruceo
  • 6,763
  • 2
  • 31
  • 52
  • I tried this, it runs without throwing an exception, but I still never see the dialog, it just goes blank, and then shows the activity once the screen has been built. – user1154644 Jun 29 '12 at 01:07
  • Then you're doing something else wrong. Are you creating the dialog in the UI Thread? And why are you using HeadLineBoard.this? Why not your context? – Cruceo Jun 29 '12 at 01:28
12

This should work for you

 public class MyActivity extends Activity {

    protected ProgressDialog mProgressDialog;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        populateTable();
    }

    private void populateTable() {
        mProgressDialog = ProgressDialog.show(this, "Please wait","Long operation starts...", true);
        new Thread() {
            @Override
            public void run() {

                doLongOperation();
                try {

                    // code runs in a thread
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mProgressDialog.dismiss();
                        }
                    });
                } catch (final Exception ex) {
                    Log.i("---","Exception in thread");
                }
            }
        }.start();

    }

    /** fake operation for testing purpose */
    protected void doLongOperation() {
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
        }

    }
}
K_Anas
  • 31,226
  • 9
  • 68
  • 81
  • hmm..still getting the leaked window problem. – user1154644 Jun 29 '12 at 00:33
  • in your solution try to add Thread.sleep(500) before the for loop and see what you get!!, – K_Anas Jun 29 '12 at 00:40
  • same behavior. I have the initializing of the ProgressDialog and the show() in the onCreate() method for the Activity, if that matters. – user1154644 Jun 29 '12 at 01:14
  • @user1154644 check my updated answer i have done some test for tried to adapt your code to it. Let me know if you find trouble and don't forget to accept and upvote the answer if it solve your problem – K_Anas Jun 29 '12 at 01:56
  • It's still throwing the leakedWindow problem, but thats because the longOperation updates the UI. – user1154644 Jun 29 '12 at 02:09
  • @user1154644 the long operation in you case is the for loop, BTW what this loop for do? – K_Anas Jun 29 '12 at 02:14
  • correct. It adds rows to a TableView. It takes a little time, so I don't want the screen to be available until that operation has concluded. – user1154644 Jun 29 '12 at 02:15
  • you are updating the ui from a non ui thread that's why you get, you should have told me from the beginning :P – K_Anas Jun 29 '12 at 02:21
  • @user1154644 why you are using thread in this case move your for loop to the oncreate method – K_Anas Jun 29 '12 at 02:22
  • so how should the populateTable() method look? – user1154644 Jun 29 '12 at 02:22
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/13194/discussion-between-k-anas-and-user1154644) – K_Anas Jun 29 '12 at 02:34
6

Instead of creating a thread, and using runOnUIThread, this is a perfect job for ASyncTask:

  • In onPreExecute, create & show the dialog.

  • in doInBackground prepare the data, but don't touch the UI -- store each prepared datum in a field, then call publishProgress.

  • In onProgressUpdate read the datum field & make the appropriate change/addition to the UI.

  • In onPostExecute dismiss the dialog.


If you have other reasons to want a thread, or are adding UI-touching logic to an existing thread, then do a similar technique to what I describe, to run on UI thread only for brief periods, using runOnUIThread for each UI step. In this case, you will store each datum in a local final variable (or in a field of your class), and then use it within a runOnUIThread block.

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
  • Helped a lot !! More at http://developer.android.com/reference/android/os/AsyncTask.html – naren Apr 28 '15 at 08:42