Search code examples
javaandroidandroid-asynctaskjava-native-interfaceokhttp

Update global variable by using a interface


I have a async class in my MainActivity.java

class Register extends AsyncTask<String, String, JSONObject> {
JSONObject json;

     @Override
     protected JSONObject doInBackground(String[] args) {

         String function = args[3];
         String email = args[2];
         String password = args[1];
         String name = args[0];

         ContentValues params = new ContentValues();
         params.put("username", name);
         params.put("password", password);
         params.put("function", function);
         if (email.length() > 0)
             params.put("email", email);

         String URL = "https://lamp.ms.wits.ac.za/home/s2090704/index.php";
         new PhpHandler().makeHttpRequest(act, URL, params, new RequestHandler() {
             @Override
             public void processRequest(String response) throws JSONException {
                json = new JSONObject(response);
                 System.out.println(json); //outputs {response: " ...",message:"..."}


             }
         });
         System.out.println(json); //outputs null
         return json;
     }
}

in doInBackground() PhpHandler processes details using OkHttp.

public class PhpHandler {

    JSONObject json;
    static String responseData = "";

    public void makeHttpRequest(final Activity a, String url,
                                      ContentValues params, final RequestHandler rh) {

        // Making HTTP request
            OkHttpClient client = new OkHttpClient();
            FormBody.Builder builder = new FormBody.Builder();

            for (String key : params.keySet()) {
                builder.add(key, params.getAsString(key));
            }

            final Request request = new Request.Builder()
                    .url(url)
                    .post(builder.build())
                    .build();

            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(@NotNull Call call, @NotNull IOException e) {

                }

                @Override
                public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                    responseData = Objects.requireNonNull(response.body()).string();
                    //System.out.println(responseData);
                   a.runOnUiThread(new Runnable() {
                       @Override
                       public void run() {
                           try {
                               rh.processRequest(responseData);
                           } catch (JSONException e) {
                               e.printStackTrace();
                           }
                       }
                   });
                }
            });

    }
}

RequestHandler is an interface that processes request on the mainUiThread.

package com.example.registration;

import org.json.JSONException;

public interface RequestHandler{
   void processRequest(String response) throws JSONException;
}

Now json doesn't update out of the processRequest method in doInBackground method of my async class Register.I know that interfaces make variables static and final is there any way to update the value of json?


Solution

  • processRequest method will be executed long after you return json from doInBackground, because makeHttpRequest performs an asynchronous http request.

    Knowing this, you will probably want to re-design this class (there is no need to wrap already asynchronous request in AsyncTask), but if you really want to do it this way, you would have to wait for your request to complete before returning the json (for example, by using CountDownLatch).

      CountDownLatch latch = new CountDownLatch(1);
      someField = null;
      AtomicReference<String> someValue = new AtomicReference<>();
    
      // don't start new threads like this, im just trying to keep this example simple
      new Thread() {
        Thread.sleep(1000); // sleep for 1 second
        someValue.set("abc"); // notice that because when using AtomicReference you assign it's value using `set` method instead of `=` operator, you can keep it as local variable instead of field class
        latch.countDown(); // reduce latch count by one
      }.run();
    
      System.out.println(someValue.get()); // null - because the assignation will happen in one second
    
      latch.await(); // this will force current thread to wait until the latch count reaches zero (initial was 1, passed to constructor)
    
      System.out.println(someValue.get()); // "abc"
    

    read more