Android runOnUiThread explanation
Asked Answered
D

3

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

}
Dearing answered 29/6, 2012 at 0:1 Comment(8)
If there are stories, add them to the table. You run this code on UI thread, not on the thread you've created.Ranie
not sure what you are suggesting?Dearing
Move all code in runOnUiThread out to void run(), leave only dialog.dismiss();Ranie
That gives me the "only the original thread that created a view...." exception.Dearing
or did I not make the correct change?Dearing
try my answer and let me know whet you getGoltz
For anyone else who comes along: ASyncTask would make this easier. 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.Love
#27654767Brigand
L
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");
            }
        }
    });
}
Latour answered 29/6, 2012 at 0:20 Comment(2)
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.Dearing
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?Latour
G
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) {
        }

    }
}
Goltz answered 29/6, 2012 at 0:27 Comment(11)
hmm..still getting the leaked window problem.Dearing
in your solution try to add Thread.sleep(500) before the for loop and see what you get!!,Goltz
same behavior. I have the initializing of the ProgressDialog and the show() in the onCreate() method for the Activity, if that matters.Dearing
@Dearing 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 problemGoltz
It's still throwing the leakedWindow problem, but thats because the longOperation updates the UI.Dearing
@Dearing the long operation in you case is the for loop, BTW what this loop for do?Goltz
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.Dearing
you are updating the ui from a non ui thread that's why you get, you should have told me from the beginning :PGoltz
@Dearing why you are using thread in this case move your for loop to the oncreate methodGoltz
so how should the populateTable() method look?Dearing
let us continue this discussion in chatGoltz
L
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.

Love answered 7/11, 2014 at 17:20 Comment(1)
Helped a lot !! More at developer.android.com/reference/android/os/AsyncTask.htmlCalycle

© 2022 - 2024 — McMap. All rights reserved.