Reputation: 21
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
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:
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
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
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
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