Access private variable from inner class (AsyncTask)

1.2k Views Asked by At

I have a problem, I am trying to access a private variable of an outer class from a doInBackground method of an AsyncTask which is the inner class. Here there is the full code.

public class MessageHandler {
private Contact receiver;
private String senderFacebookId;
private String message;
private final String TAG = "MessageHandler";
private Context context;
boolean sentResult;

public MessageHandler(Contact receiver, String senderFacebookId, String message, Context context) {
    this.receiver = receiver;
    this.senderFacebookId = senderFacebookId;
    this.message = message;
    this.context=context;
    this.sentResult = false;
}

public void send(){
    Log.i(TAG, "Sending message to " + receiver.getName() + " receiver id: " + receiver.getFacebook_id() + " sender id: " + senderFacebookId + " message: " + message);

    new SenderAsync().execute(senderFacebookId,message, receiver.getFacebook_id());
    if(this.sentResult==true){
        Toast toast = Toast.makeText(this.context, "Message Sent", Toast.LENGTH_LONG);
        toast.show();

    }else{
        Toast toast = Toast.makeText(this.context, "ERROR: Message not Sent", Toast.LENGTH_LONG);
        toast.show();
    }
}



private class SenderAsync extends AsyncTask<String,String,String> {

    @Override
    protected void onPreExecute(){
        super.onPreExecute();
    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
    }

    @Override
    protected String doInBackground(String... params) {
        HttpClient client = new DefaultHttpClient();

        try {
            List<NameValuePair> parameter = new ArrayList<>(1);
            parameter.add(new BasicNameValuePair("regId", "empty"));
            parameter.add(new BasicNameValuePair("sender_id", params[0]));
            parameter.add(new BasicNameValuePair("receiver_facebook_id", params[2]));

            parameter.add(new BasicNameValuePair("message", params[1]));

            String paramString = URLEncodedUtils.format(parameter, "utf-8");
            HttpGet get = new HttpGet(ProfileFragment.SERVER_URL_SEND_MESSAGE+"?"+paramString);

            Log.i(TAG, paramString);
            HttpResponse resp = client.execute(get);
            System.out.println("SREVER RESPONSE " + resp.getStatusLine().getStatusCode());

            //THIS IS THE VARIABLE THAT I WANT TO ACCESS
            if(resp.getStatusLine().getStatusCode()==200){
                MessageHandler.this.sentResult = true;
            }



        } catch (IOException e) {

            Log.i(TAG,"Error :" + e.getMessage());
        }
        return null;
    }
}

}

The variable that I am trying to access is the boolean variable sentResult. I also print out the response of the server which is always 200. Even if I remove the if condition and I set it to be true in any case, it looks like that that line of code is never executed and the variable not accessed, so it is always false.

4

There are 4 best solutions below

1
On BEST ANSWER

The entire point of an async task is that it is asynchronous. If you execute a task, you will not get the results back on your next line of code. In order to evaluate the result, you should be using the onPostExecute callback method.

@Override
protected void onPostExecute(String s) {
    if(sentResult==true){
        Toast toast = Toast.makeText(this.context, "Message Sent", Toast.LENGTH_LONG);
        toast.show();
    }else{
        Toast toast = Toast.makeText(this.context, "ERROR: Message not Sent", Toast.LENGTH_LONG);
        toast.show();
    }
}

Also, if you were to change your method signatures, you wouldn't even need an external variable.

private class SenderAsync extends AsyncTask<String,String,Boolean> {

@Override
protected void onPostExecute(Boolean sent) {
    if(sent == true){
        Toast toast = Toast.makeText(this.context, "Message Sent", Toast.LENGTH_LONG);
        toast.show();
    }else{
        Toast toast = Toast.makeText(this.context, "ERROR: Message not Sent", Toast.LENGTH_LONG);
        toast.show();
    }
}

@Override
protected Boolean doInBackground(String... params) {
    try {
        ...
        if (resp.getStatusLine().getStatusCode() == 200) {
            return true;
        }
    }
    catch (IOException e) {

    }

    return false;
}
2
On

Create Constructor for SenderAsync;

public SenderAsync(Context context, String senderId, String msg, Contact receiver)

Call it this way;

new SenderAsync(senderFacebookId,message, receiver.getFacebook_id()).execute();

And you need to get your result in onPostExecute. void onPostExecute(String returnedValue) { // Run the if statement you want here }

0
On

You are trying to verify sentResult right after you tell the AsyncTask to do its work. The AsyncTask does what it has to do on a separate thread, in parallel. So until it finishes, the sentResult is unchanged.

What I suggest is to put your Toast logic in onPostExecute.

0
On

You are using AsyncTask incorrectly. AsyncTask should return results in onPostExecute() and your UI should have a seperate method onPostExecute() calls (hence the asynchronous name). For what you are trying to accomplish, you should be doing it like this:

public void send() {
    new SenderAsync().execute(senderFacebookId,message, receiver.getFacebook_id());
}

public void processResult(boolean result) {
  String resultMsg = result ? "Message Sent" : "ERROR: Message not Sent";
  Toast.makeText(this.context, resultMsg, Toast.LENGTH_LONG).show();
}

private class SenderAsync extends AsyncTask<String, String, Boolean> {
  ...
  @Override
    protected String doInBackground(String... params) {
      ...
      try {
        ...
        return (resp.getStatusLine().getStatusCode() == 200)
      }
      ...
      return false;
    }

    @Override
    protected void onPostExecute(Boolean result) {
        processResult(result);
    }
}