n8.premo
n8.premo

Reputation: 21

AsyncTask onPostExecute isnt' getting called

I'm trying to implement a basic login screen for an android app. The flow is as follows:
1) User enters login information and hits submit
2) A LoginRequest which extends AsyncTask is created and executed.
3) The doInBackground will fire some http calls to validate the user credentials
4) The onPostExecute should be getting called to set the loginResults
5) Ui thread sees the login results and continues accordingly.

I'm been simplifying the code to get to the root issue but haven't had any luck so far. Here is the simplified code that still repros the issue.

Inside my activity:

private void tryLogin(String email, String password)
{
    this.showProgress(true);
    LoginHelper loginHelper = new LoginHelper();
    LoginResult result = loginHelper.tryLogin(email, password);
    this.showProgress(false);
}

This gets called from my submit buttons on click listener.

Inside LoginHelper:

TestClass test = new TestClass();
public LoginResult tryLogin(String mobileNumber, String password, int deviceId)
{
    String loginUrl = "...";
    new LoginRequest(test).execute(loginUrl);

    while (test.result == null)
    {
        try {
            Thread.sleep(1000);
        }
        catch (Exception e)
        {
            //...
        }
    }
    return test.result;
}

This will execute the AsyncTask and wait for the result being continuing.

LoginRequest:

public class LoginRequest extends AsyncTask<String, Void, LoginResult>
    TestClass test;

    public LoginRequest(TestClass test)
    {
        this.test = test;
    }
    @Override
    protected LoginResult doInBackground(String... params) {

        LoginResult ret = null;
        ret = new LoginResult(1,"test");
        return ret;
    }

    @Override
    protected void onPostExecute(LoginResult result) {
         this.test.result = result;
    }
}

I run this through the debugger with breakpoints inside the doInBackground and onPostExecute. The doInBackground executes correctly and returns the LoginResult value, but the onPostExecute breakpoint never gets hit, and my code will wait in the while loop in LoginHelper.

Upvotes: 0

Views: 2036

Answers (4)

Vojtěch Pešek
Vojtěch Pešek

Reputation: 1090

You are basically checking the whole time the variable 'result' of your LoginRequest. But that's not, how AsyncTask works.

From Docs:

AsyncTask allows you to perform asynchronous work on your user interface. It performs the blocking operations in a worker thread and then publishes the results on the UI thread, without requiring you to handle threads and/or handlers yourself.

You can do your work in doInBackground() method and the publish you results in onPostExecute().

onPostExecute runs on UI Thread, to allow you change elements, show the result or whatever you want to do. Your problem is, that you are the whole time blocking the UI Thread with your checking method in tryLogin()

So how to solve it?

Remove the checking method:

public void tryLogin(String mobileNumber, String password, int deviceId)
{
    // Starts AsynTasks, handle results there
    String loginUrl = "...";
    new LoginRequest().execute(loginUrl);
}

in AsyncTask:

public class LoginRequest extends AsyncTask<String, Void, LoginResult>

    // Removed Constructor, if you need to pass some other variables, add it again

    @Override
    protected LoginResult doInBackground(String... params) {

        // TODO: Change this to actual Http Request
        LoginResult ret = null;
        ret = new LoginResult(1, "test");
        return ret;
    }

    @Override
    protected void onPostExecute(LoginResult result) {
         // Now the result arrived!
         // TODO: Use the result
    }
}

More Thoughts:

  1. You probably want to store user credentials. If so, make sure the are safe. Link
  2. You might want, depending on results, change some UI. Here's an example:

AsyncTask:

public class LoginRequest extends AsyncTask

    private Activity activity;

    // Constructor
    public LoginRequest(Activity activity) {
       this.activity = activity;
    }

    @Override
    protected LoginResult doInBackground(String... params) {

        // TODO: Change this to actual Http Request
        LoginResult ret = null;
        ret = new LoginResult(1, "test");
        return ret;
    }

    @Override
    protected void onPostExecute(LoginResult result) {

         ActivityLogin acLogin = (ActivityLogin) activity;

         if(result.equals("ok")) {
            Button loginButton = (Button) acLogin.findViewById(R.id.login-button);
            loginButton.setBackgroundColor(Color.GREEN);

            //Finish LoginActivity
            acLogin.finish();
         }
         else {
            //TODO: Fail Handling
         }
    }
}

And the start it like this:

new LoginRequest(loginActivity).execute(loginUrl);

I didnt tested the code.

Upvotes: 1

krishna5688
krishna5688

Reputation: 1180

Temporary solution : You can add this.test.result = result; in the doInbackground() method.

@Override
 protected LoginResult doInBackground(String... params) {

            LoginResult ret = null;
            ret = new LoginResult(1, "test");
            this.test.result = result;
            return ret;
 }

Please post full code to get proper solution.

Upvotes: 0

Akshay Kulkarni
Akshay Kulkarni

Reputation: 729

Try This

    public class LoginRequest extends AsyncTask<String, Void, LoginResult>
    {
    TestClass test;
        LoginResult ret = null;

    public LoginRequest(TestClass test)
    {
        this.test = test;
    }
    @Override
    protected Boolean doInBackground(String... params) {
        ret = new LoginResult(1,"test");
        return true;
    }

    @Override
    protected void onPostExecute(Boolean success) {
        if(success)
            this.test.result = result;
    }
   }

Upvotes: 0

Denominator
Denominator

Reputation: 216

It's AsyncTask so it's calling the LoginRequest and while(test.result) at the same time. You got stuck in the while loop because test.result is not done returning yet. test.result is done in onPostExecute(), so if you move that while loop in that function it will work and onPostExecute() will get called. One way to solve this problem is to implement a callback interface. Put the while loop in the overrided callback method. refer to my answer here: how to send ArrayList(Bitmap) from asyncTask to Fragment and use it in Arrayadapter

Upvotes: 0

Related Questions