7

My application fetches some html code from the internet and when done , displays it on the devices screen. Since it takes about 3-4 seconds to do that , in this time the screen stays black , I'd like to use a progress dialog. This is my code :

package com.nextlogic.golfnews;



// ALL THE IMPORTS ....

public class Activity1 extends Activity {

    private ProgressDialog progressDialog;
 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main2);

        progressDialog = ProgressDialog.show(Activity1.this, "", "Loading...");
        new Thread() 
        {
          public void run() 
          {

             try
               {
                sleep(2000);

          // HERE I'VE PUT ALL THE FUNCTIONS THAT WORK FOR ME
 }
    catch (Exception e)
    {
        Log.e("tag",e.getMessage());
    }
// dismiss the progressdialog   
  progressDialog.dismiss();
 }
}.start();

The program works but it doesn't display anything anymore. I have one error in logcat :

Only the original thread that created a view hierarchy can touch its views.

Could you please help me ? Thanks in advance.

Teo
  • 3,394
  • 11
  • 43
  • 73
  • The given answers are correct, but I'd like to add something. ProgressDialogs have 2 styles: STYLE_SPINNER (default) and STYLE_HORIZONTAL. According to the [ui dialogs](http://developer.android.com/guide/topics/ui/dialogs.html) we should follow the [design guidelines for Progress & Activity](http://developer.android.com/design/building-blocks/progress.html) and use a STYLE_HORIZONTAL (if relevant and possible). On this matter I found [this tutorial](http://www.pavanh.com/2013/04/android-progress-dialog-example.html) very useful. Now you have the choice which style of ProgressDialog you want... – T_D Jun 03 '13 at 16:26

5 Answers5

17

The error is explicative enough. To update one visual object you must run the changes inside main thread. A quick and dirty fix could be calling the update code inside runOnUiThread().

However in your case I would use an AsyncTask to download and update the progress of the progress bar. The task has the property to run on UI thread when it ends (so you can update the views there, such as dismissing the progress dialog)

Here is an example how to use an AsyncTask to display a download progress dialog.

Update

Stackoverflow already has the answers to all your question. Here is an example of an AsyncTask to download some content and display the download progress. Just what you want.

Update 2

Ok here is your code using an AsyncTask:

public class Activity1 extends Activity
{
    private ProgressDialog progressDialog;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        new AsyncTask<Integer, Integer, Boolean>()
        {
            ProgressDialog progressDialog;

            @Override
            protected void onPreExecute()
            {
                /*
                 * This is executed on UI thread before doInBackground(). It is
                 * the perfect place to show the progress dialog.
                 */
                progressDialog = ProgressDialog.show(Activity1.this, "",
                        "Loading...");
            }

            @Override
            protected Boolean doInBackground(Integer... params)
            {
                if (params == null)
                {
                    return false;
                }
                try
                {
                    /*
                     * This is run on a background thread, so we can sleep here
                     * or do whatever we want without blocking UI thread. A more
                     * advanced use would download chunks of fixed size and call
                     * publishProgress();
                     */
                    Thread.sleep(params[0]);
                    // HERE I'VE PUT ALL THE FUNCTIONS THAT WORK FOR ME
                }
                catch (Exception e)
                {
                    Log.e("tag", e.getMessage());
                    /*
                     * The task failed
                     */
                    return false;
                }

                /*
                 * The task succeeded
                 */
                return true;
            }

            @Override
            protected void onPostExecute(Boolean result)
            {
                progressDialog.dismiss();
                /*
                 * Update here your view objects with content from download. It
                 * is save to dismiss dialogs, update views, etc., since we are
                 * working on UI thread.
                 */
                AlertDialog.Builder b = new AlertDialog.Builder(Activity1.this);
                b.setTitle(android.R.string.dialog_alert_title);
                if (result)
                {
                    b.setMessage("Download succeeded");
                }
                else
                {
                    b.setMessage("Download failed");
                }
                b.setPositiveButton(getString(android.R.string.ok),
                        new DialogInterface.OnClickListener()
                        {

                            @Override
                            public void onClick(DialogInterface dlg, int arg1)
                            {
                                dlg.dismiss();
                            }
                        });
                b.create().show();
            }
        }.execute(2000);

        new Thread()
        {
            @Override
            public void run()
            {

                // dismiss the progressdialog
                progressDialog.dismiss();
            }
        }.start();
    }
}
Community
  • 1
  • 1
Fernando Miguélez
  • 11,196
  • 6
  • 36
  • 54
  • Could you please assist me ? I am new to android and I didn't fully understand that example . – Teo Oct 10 '11 at 13:54
  • The thing is .. I don't want to change my functions because the program works just fine , a bit slow . I want to put those functions in a background thread and while those functions are executing , I want to display the progress dialog. – Teo Oct 10 '11 at 14:16
  • thanks again , I am sorry to bother you but where do I put all my code that does all the things ( taking content from the internet , displaying it on the screen)?? .. if I put it under `Thread.sleep(params[0]);` instead of `// HERE I'VE PUT ALL THE FUNCTIONS THAT WORK FOR ME` it crashes. – Teo Oct 10 '11 at 14:48
  • I don't understand what should I put here : `protected Boolean doInBackground(Integer... params)` instead of integer and params .. – Teo Oct 10 '11 at 14:51
  • Your answer seems the most appropriate ... I just want to make it work . Then , you will definetely get the vote . – Teo Oct 10 '11 at 14:54
  • Instead of Thread.sleep(params[0]) place there your code. If you need other type of params just change "Integer" for the type of object you want. I assume you are not very used to working with generics in Java. – Fernando Miguélez Oct 13 '11 at 07:47
4

You need to do this way

runOnUiThread(new Runnable() {
    public void run() {
      // Do Your Stuff
    }});
MKJParekh
  • 34,073
  • 11
  • 87
  • 98
  • and where do I dismiss the progressDialog ? – Teo Oct 10 '11 at 14:11
  • i suppose you just make a function in that write above code and in place of comment write code to dismiss dialog and call the fun from ur task whenever u need – MKJParekh Oct 11 '11 at 07:18
2

Dismiss your dialog like this:

Handler handler = new Handler();
handler.post(new Runnable(){
   public void run(){
      progressDialog.dismiss();
   }
});
Vineet Shukla
  • 23,865
  • 10
  • 55
  • 63
  • I've replaced `progressDialog.dismiss();` with your code . Now the program crashes. – Teo Oct 10 '11 at 13:47
  • I did this , the program crashes .. firs it says : `Can't create handler inside thread that has not called Looper.prepare()` and then `String out of bounds` – Teo Oct 10 '11 at 14:27
  • put the runnable out of onCreate() like this:final Runnable mUpdateResults = new Runnable() { public void run() { progressDialog.dismiss(); } }; and then from thread call it like this:handler.post(mUpdateResults); – Vineet Shukla Oct 10 '11 at 14:31
  • it is loading and it is not ending the progressDialog – Teo Oct 10 '11 at 14:45
1

Create a UI thread after completing network operation

runOnUiThread(new Runnable() { 
            @Override 
            public void run() { 
             progressDialog.dismiss();

            } 
        });
Sandeep Kumar P K
  • 7,412
  • 6
  • 36
  • 40
0

The top answer works great, so here is an example to implement an AsyncTask in MonoDroid (thanks to Greg Shackels): http://mono-for-android.1047100.n5.nabble.com/AsyncTask-td4346647.html

samus
  • 6,102
  • 6
  • 31
  • 69