41

I have a function, AppHelper.isOnline(Context context), I call in various parts of my application to check that a session didn't timeout before making an HTTP request.

public void onClick(View v) {
        Intent intent = null;
        switch (v.getId()) {

        case R.id.buttonPagamenti:
            if (AppHelper.isOnline(this))
            {
                //here AppHelper.isOnline should have finished it's async task
                intent = new Intent(this, OrdineCreaActivity.class);
                this.startActivityForResult(intent, R.id.buttonPagamenti);
            }
            break;
...

Inside AppHelper.isOnline(), I am executing an AsyncTask that logs in, thus making a network request, which can't be run on UI because otherwise I get an exception. I need to wait for it to finish BEFORE resuming with the code inside the if. How can I do this ?

Problem is the activity starts firsts, then the AsyncTask executes, so when the activity expects a valid logged in session, it breaks.

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
max4ever
  • 11,909
  • 13
  • 77
  • 115

4 Answers4

83

You have two options:

Either use the AsyncTask's method get(long timeout, TimeUnit unit) like that:

task.get(1000, TimeUnit.MILLISECONDS);

This will make your main thread wait for the result of the AsyncTask at most 1000 milliseconds (as per @user1028741 comment: actually there is also infinetly waiting method - AsyncTask#get() which might also do the work for you in some cases).

Alternatively you can show a progress dialog in the async task until it finishes. See this thread (No need for me to copy past the code). Basically a progress dialog is shown while the async task runs and is hidden when it finishes.

You have even third option:" if Thread is sufficient for your needs you can just use its join method. However, if the task is taking a long while you will still need to show a progress dialog, otherwise you will get an exception because of the main thread being inactive for too long.

Community
  • 1
  • 1
Boris Strandjev
  • 46,145
  • 15
  • 108
  • 135
  • i tried the join, but the problem is the async.exec() doesn't start before the join kicks in, so the app holds indefinetely, tommorow going to try task.get – max4ever Apr 03 '12 at 17:50
  • 2
    the async task does have a progress dialog but it doesn't stop the new activity from starting – max4ever Apr 03 '12 at 17:52
  • i have one little problem, the async shows a progress bar, however with task.get() during async doInBackground() nothing is drawn, the async finishes and then the dialog quickly appears and disappears – max4ever Apr 04 '12 at 09:46
  • 2
    You can also task.get() without parameters, this way it will wait for the whole computation to finish, and only then continue. – user1028741 May 18 '14 at 14:30
  • @user1028741 added in the answer, hopefully you do not mind (I have included attribution) – Boris Strandjev May 18 '14 at 17:36
  • d= (-_- ) Nice! but sometimes `get(...)` returns before `onCompleted(...)` is called (for me causing a race condition, workaround: `while(task.getStatus() != AsyncTask.Status.FINISHED) { Thread.sleep(100); }`). – Top-Master Mar 12 '21 at 20:50
3

try using

if (AppHelper.isOnline(this))
        {
            while(!task.isCancelled()){
               // waiting until finished protected String[] doInBackground(Void... params)          
              } 
            intent = new Intent(this, OrdineCreaActivity.class);
            this.startActivityForResult(intent, R.id.buttonPagamenti);
        }    

For more information read http://developer.android.com/reference/android/os/AsyncTask.html

Rafiq
  • 2,000
  • 2
  • 21
  • 27
2

Rafiq's response did not work for me - the app hung. I think the reason has to do with the nature of isCancelled(): "Returns true if this task was cancelled before it completed normally." If the task completes normally (i.e. is not cancelled) then while(!task.isCancelled()) { } will loop forever.

To solve this create a Boolean flag that you instatiate to false and then flip to true in task.onPostExecute(). Then do while(!flag) { } before switching Activities. Additionally, if you'd like to give the main thread a 'break' to let the AsyncTask process a little faster, you can do try this:

while (!flag) {
    try { Thread.sleep(100); }
    catch (InterruptedException e) { e.printStackTrace(); }
}

It seems to be working well for me.

Mark Cramer
  • 2,614
  • 5
  • 33
  • 57
  • This is exactly what I'm trying to do, but for some reason the method onPostExecute is not being called so the UI gets stuck in the Thread.sleep method. – EmilioSG Jul 11 '13 at 11:44
  • 1
    @Emiliosg - Are you sure that your AsyncTask is completing? If the AsyncTask never completes then you'll never get 'onPostExecute()' and you'll hang waiting for it. Try adding some logging to your 'doInBackground()' to make sure that it's successfully doing what it's supposed to be doing. – Mark Cramer Jul 11 '13 at 16:34
  • It is not a good idea to use busy wait, please refer to https://www.facebook.com/arig/posts/10105815276466163 – Yuchen Jun 27 '16 at 15:42
  • This is not a busy wait, but a poll: http://c2.com/cgi/wiki?BusyWaiting. – Mark Cramer Jun 27 '16 at 16:07
1
intent = new Intent(this, OrdineCreaActivity.class);
context.startActivityForResult(intent, R.id.buttonPagamenti);

Write the above lines in onPostExecute() of you AysncTask. Because if we are using AsyncTask it wont wait there until the task complete.

Jared
  • 1,449
  • 2
  • 19
  • 40
Shankar Agarwal
  • 34,573
  • 7
  • 66
  • 64
  • yes but sometimes i don't need to start a new activity maybe i do other stuff, i need to stop the main ui thread and wait for the async – max4ever Apr 03 '12 at 17:50
  • i didnt get you can you be more specific – Shankar Agarwal Apr 03 '12 at 17:52
  • at some points in my application i need check if the user is logged in and if not i need to auto login for him, i would like to avvoid to make 3000 different callbacks(for the onPostExecute to call) – max4ever Apr 03 '12 at 18:07
  • Try to maintain a bool variable in your app to know whether is logged in or not just have a if else case and handle your requirement. – Shankar Agarwal Apr 04 '12 at 02:29
  • How can you even think like that? Your code seems pretty legit to me. – ssi-anik Aug 02 '15 at 04:27