QWERTY
QWERTY

Reputation: 2315

Android AsyncTask keeps return opposite value

I got a problem with AsyncTask at Android Studio. What I am trying to do is before I create a new user, I am checking if the username and email exist in my database. Here is the part where I call the create AsyncTask:

new SignupAsyncTask(getBaseContext()).execute(userModel);
if(SignupAsyncTask.successCheck == false){
    Toast.makeText(getBaseContext(), "Failed", Toast.LENGTH_SHORT).show();
} else if(SignupAsyncTask.successCheck == true){
    Toast.makeText(getBaseContext(), "Success", Toast.LENGTH_SHORT).show();
}

Inside my AsyncTask, I am getting all user. Then I perform a loop to check if there is any matching username or password. If there is, I set the successCheck to false.

public class SignupAsyncTask extends AsyncTask<User, Integer, Boolean> {
    ArrayList<User> list = new ArrayList<User>();
    DB_User userCtrl = new DB_User();
    Context context;
    public static boolean successCheck = false;

    public SignupAsyncTask(){}

    public SignupAsyncTask(Context context){
        this.context = context;
    }

    @Override
    protected Boolean doInBackground(User... params) {
        try {
            list = userCtrl.getAllUser();
            for(int i = 0; i < list.size(); i++){
                User userObj = list.get(i);
                if(params[0].getUserName().equals(userObj.getUserName())){
                    successCheck = false;
                    break;
                }
                else if (params[0].getEmail().equals(userObj.getEmail())){
                    successCheck = false;
                    break;
                } else{
                    successCheck = true;
                    break;
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

        if(successCheck == true){
            userCtrl.SignupUser(params[0]);
        }
        return successCheck;
    } 

    @Override
    protected void onPostExecute(Double result){

    }

    @Override
    protected void onProgressUpdate(Integer... progress) {

    }
}

The problem that I have encountered now is for the first time when I am testing with a non-duplicate username and email, it can insert into database but somehow the toast printed out 'Failed'.

Then, when I try with another duplicate record, it does not insert into database as I set my username and email to be UNIQUE but the toast is printing out 'Success'.

It is operated in the opposite way as my code logic. Any ideas?

Thanks in advance

EDIT

public class SignupAsyncTask extends AsyncTask<User, Integer, Boolean> {
ArrayList<User> list = new ArrayList<User>();
DB_User userCtrl = new DB_User();
Context lcontext;
public static boolean successCheck = false;

public SignupAsyncTask(){}

public SignupAsyncTask(Context context){
    lcontext = context;
}

@Override
protected Boolean doInBackground(User... params) {
    try {
        list = userCtrl.getAllUser();
        for(int i = 0; i < list.size(); i++){
            User userObj = list.get(i);
            if(params[0].getUserName().equals(userObj.getUserName())){
                successCheck = false;
                break;
            }
            else if (params[0].getEmail().equals(userObj.getEmail())){
                successCheck = false;
                break;
            } else{
                successCheck = true;
                break;
            }
        }
    } catch (JSONException e) {
        e.printStackTrace();
    }

    return successCheck;
}

@Override
protected void onPostExecute(Boolean result){
    if(successCheck)
    {
        //userCtrl.SignupUser(userobject);
        Log.d("Check","Ran Success");
        Toast.makeText(lcontext, "Success", Toast.LENGTH_SHORT).show();
    }
else {
        Log.d("Check","Ran Fail");
        Toast.makeText(lcontext, "Failed", Toast.LENGTH_SHORT).show();
    }
}

@Override
protected void onProgressUpdate(Integer... progress) {

}

Upvotes: 1

Views: 117

Answers (3)

ישו אוהב אותך
ישו אוהב אותך

Reputation: 29794

It's because of AsyncTask, as its name, is an asynchronous task. You need to test the result in your SignupAsyncTask class.

Add the logic to your AsyncTask onPostExecute():

@Override
protected void onPostExecute(Boolean result){
  if(result == false){
    // Process if false
  } else if(result == true){
    // Process if true
  }
}

Because you can't access UI thread from SignupAsyncTask (where your class is not a member class of your caller class), you need to define an interface as listener mechanism in your caller class to receive the result from your AsyncTask. So whenever there is a change in data, it will inform the caller who implements the interface.

Something like:

public interface OnSuccessCheckReceived{
  void onSuccessCheckReceived(boolean isSuccess);
}

Then you add the callback interface to SignupAsyncTask:

public class SignupAsyncTask extends AsyncTask<User, Integer, Boolean> {
  ...

  OnSuccessCheckReceived callBack;
  public SignupAsyncTask(){}

  public SignupAsyncTask(Context context, OnSuccessCheckReceived callBack){
    this.context = context;
    this.callBack = callBack;
  }

  ...

  @Override
  protected void onPostExecute(Boolean result){
    //if(result == false){
    //  // Process if false
    //  callBack.onSuccessCheckReceived(false); // Tell the caller 
    //} else if(result == true){
    //  // Process if true
    //}

    // a more compact code
    callBack.onSuccessCheckReceived(result); // Tell the caller 
  }

Then you need to implement the listener interface to your caller class. Something like:

public class YourCallerActivity implements OnSuccessCheckReceived {
  ...
  @Override 
  public void onSuccessCheckReceived(boolean isSuccess) {
    if(isSuccess){
        Toast.makeText(getBaseContext(), "Failed", Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(getBaseContext(), "Success", Toast.LENGTH_SHORT).show();
    }
  }
  ...
}

Then you must call your AsyncTask with:

// this is pointing to your implemented interface.
new SignupAsyncTask(getBaseContext(), this).execute(userModel); 

Suggestion,

Better if you don't add a context to an AsyncTask, because when your app terminated and AsyncTask not yet finished its job, your AsyncTask will throw an Error because the previous context its pointing is already gone.

So you need to change your SignupAsyncTask constructor to:

public SignupAsyncTask(OnSuccessCheckReceived callBack){
  //this.context = context; Remove this.
  this.callBack = callBack;
}

and call the SignupAsyncTask with:

new SignupAsyncTask(this).execute(userModel);

UPDATE

As @trooper pointing out, you need to change your:

@Override
protected void onPostExecute(Double result){

}

to

@Override
protected void onPostExecute(Boolean result){

}

So to tell the caller class, you need to tell about the result:

@Override
protected void onPostExecute(Boolean result){
  // This is a more compact code that your previous code.
  callBack.onSuccessCheckReceived(result); // Tell the caller 
}

based on the other signatures in your AsyncTask.

Upvotes: 2

Ankit Khare
Ankit Khare

Reputation: 1385

Please modify your code like this

    private ArrayList<User> list;
        private DB_User userCtrl;
        private Context context;
        private SendResponse mRes;

        public SignupAsyncTask(Context context,SendResponse res){
            this.context = context;
            userCtrl = new DB_User();
            list = new ArrayList<User>();
            mRes = res;
        }

        @Override
        protected Boolean doInBackground(User... params) {
            try {
                list = userCtrl.getAllUser();
                for(User userObj:userCtrl.getAllUser()){
                    if(params[0].getUserName().equals(userObj.getUserName())
                            || params[0].getEmail().equals(userObj.getEmail()))
                       return false;
                }else{
                    userCtrl.SignupUser(params[0]);
                      return true;
}
            } catch (JSONException e) {
                e.printStackTrace();
                return false;
            }
                return true;
        }

        @Override
        protected void onPostExecute(Boolean result){


                //notify through interface to activity or fragment wherever you want to
                //mRes.sendResponse(result);
        }

        @Override
        protected void onProgressUpdate(Integer... progress) {

        }

Upvotes: 0

Monish Kamble
Monish Kamble

Reputation: 1488

Put your logic inside onPostExecute() :

protected void onPostExecute(Boolean result){
    if(successCheck){
        Toast.makeText(getBaseContext(), "Success", Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(getBaseContext(), "Failed", Toast.LENGTH_SHORT).show();
    }
}

AsyncTask executes asynchronously i.e., It does not run on a Main thread. It spawns a separate thread known as Worker thread, executes its logic and then post back the results onto the Main thread.

Edit 1

Change your code as below :

public class SignupAsyncTask extends AsyncTask<User, Integer, Boolean> {
    ArrayList<User> list = new ArrayList<User>();
    DB_User userCtrl = new DB_User();
    Context context;
    public static boolean successCheck = false;
    User user = null;

    public SignupAsyncTask(){}

    public SignupAsyncTask(Context context){
        this.context = context;
    }

    @Override
    protected Boolean doInBackground(User... params) {
        try {
            user = params[0];
            list = userCtrl.getAllUser();
            for(int i = 0; i < list.size(); i++){
                User userObj = list.get(i);
                if(user.getUserName().equals(userObj.getUserName())){
                    successCheck = false;
                    break;
                }
                else if (user.getEmail().equals(userObj.getEmail())){
                    successCheck = false;
                    break;
                } else{
                    successCheck = true;
                    break;
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return successCheck;
    } 

    @Override
    protected void onPostExecute(Boolean result){
        if(result){
            Toast.makeText(getBaseContext(), "Success", Toast.LENGTH_SHORT).show();
            //Call SignupUser Code Here...
            if(user != null) {
                userCtrl.SignupUser(user);   
            }
        } else {
            Toast.makeText(getBaseContext(), "Failed", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {

    }
}

Upvotes: 1

Related Questions