0

I have a piece of code which connects to a server and then logs in. While these two tasks (connect to server and login) are being executed, a progress dialog appears.

final ProgressDialog pd = new ProgressDialog(getActivity());
pd.setIndeterminate(true);
pd.setCancelable(false);

// While connecting to the server, the dialog should say the following:
pd.setTitle("Connecting...");
pd.setMessage("Connecting to " + hostname + "...");

pd.show();

new AsyncTask<Void, Void, Void>() {

    @Override
    protected Void doInBackground(Void... params) {
        try {

            // First task is executed. Progress dialog should say "Connecting..."
            executeTask1();

            // When the first task (connecting to server) is ready, I want the title
            // and the message of the progress dialog to be changed into this:
            pd.setTitle("Logging in"); //// MARKED LINE, see below. ////
            pd.setMessage("Trying to log in to server...");

            // Second task is executed.
            executeTask2();

            // Shows a screen and dismisses the ProgressDialog.
            showScreen(ScreenConstant.LIST_RESIDENTS);
            pd.dismiss();
        }
        catch (Exception exc) { }
    }
}

But I ran into two problems:

  1. A RuntimeException is raised when the MARKED LINE (see above) is executed: "Only the original thread that created a view hierarchy can touch its views"
  2. The login task gets a response from the server, but this response is asynchronous.

I want a ProgressDialog to appear with the text "Connecting..." while the connection attempt is being executed. After the connection is successful, I want the text of the progress dialog to be changed into "Logging in...", while the login attempt is being performed.

Now how should I achieve this?

EDIT

Notice that executeTask2() triggers a task to be run in a different thread; it sends a login request to the server, therefore I need to wait until that thread signals me when it's ready.

MC Emperor
  • 22,334
  • 15
  • 80
  • 130

2 Answers2

0

Any code that touches the UI should be done on the Main Thread, so you'll need to use onProgressUpdate() and publishProgress() to facilitate this.

eg:

public void onProgressUpdate(Void... progress){
    super.onProgressUpdate(progress);
    pd.setTitle("Logging in");
    pd.setMessage("Trying to log in to server..."):
}

and in your doInBackground() method:

executeTask1();
//task one finished, update UI
publishProgress();

In addition to this, you should dismiss your ProgressDialog in onPostExecute(), as this is also executed on the Main Thread

panini
  • 2,026
  • 19
  • 21
  • Thanks for this answer. However, this would only solve problem #1 as described in my question. But how can I pause the execution of the thread, to wait for the server response to my login request? (Do I need `Thread.join()` perhaps?) – MC Emperor Jun 18 '14 at 11:36
  • why not move the code from the second Tasks doInBackground() into the first tasks doInBackground()? it seems a waste to use two different AsyncTasks for this – panini Jun 18 '14 at 20:30
  • What do you mean? I do not use two different `AsyncTask`s, see question. – MC Emperor Jun 19 '14 at 09:52
  • you're using a different thread for executeTask2(), why? you already have a background thread when executing in doInBackground(), why do you need another? – panini Jun 19 '14 at 20:50
  • so dismiss your ProgressDialog in the success/failure callback of the library async task – panini Jun 21 '14 at 21:53
0

You need to run the progress dialog in the main thread, only the thread that create the view can update or call it thus giving you that exception.

sample:

    @Override
    protected Void doInBackground(Void... params) {
        try {

            // First task is executed. Progress dialog should say "Connecting..."
            executeTask1();

            // When the first task (connecting to server) is ready, I want the title
            // and the message of the progress dialog to be changed into this:
            getActivity().runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    pd.setTitle("Logging in"); //// MARKED LINE, see below. ////
                    pd.setMessage("Trying to log in to server...");
                }
            });


            // Second task is executed.
            executeTask2();

            // Shows a screen and dismisses the ProgressDialog.
            showScreen(ScreenConstant.LIST_RESIDENTS);

            getActivity().runOnUiThread(new Runnable() {

                @Override
                public void run() {
                 pd.dismiss();  


                }
            });

        }
        catch (Exception exc) { }
    }

note:

It would be wise to dismiss the dialog in the post execute method of the Asynctask that it run in the main thread.

Rod_Algonquin
  • 26,074
  • 6
  • 52
  • 63
  • Thanks. But this would only solve problem #1 as described in my question; problem #2 remains unsolved. (See comment below @panini's answer.) – MC Emperor Jun 18 '14 at 11:37