How to make StringRequest work 100% of time Android

Viewed 21

I have a StringRequest reading from an API, but it only sometimes works:

System.out.println("Getting data");
String myUrl = "https://api.quotable.io/random";

StringRequest myRequest = new StringRequest(Request.Method.GET, myUrl,
        response -> {
            try{
                // Create a JSON object containing information from the API.
                JSONObject object = new JSONObject(response);
                currentQuote = object.getString("content");
                currentQuoteAuthor = object.getString("author");
                System.out.println("Set");

            } catch (JSONException e) {
                e.printStackTrace();
            }
        },
        volleyError -> Toast.makeText(MainActivity.this, volleyError.getMessage(), Toast.LENGTH_SHORT).show()
);

RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(myRequest);
System.out.println(currentQuote);
System.out.println(currentQuoteAuthor);

output

2022-05-25 13:50:34.758 10165-10165/com.example.lab I/System.out: Getting data
2022-05-25 13:50:34.768 10165-10165/com.example.lab I/System.out: When the world is so complicated, the simple gift of friendship is within all of our hands.
2022-05-25 13:50:34.768 10165-10165/com.example.lab I/System.out: Maria Shriver
2022-05-25 13:50:34.822 10165-10165/com.example.lab I/System.out: Set
2022-05-25 13:50:37.038 10165-10165/com.example.lab I/System.out: Getting data
2022-05-25 13:50:37.050 10165-10165/com.example.lab I/System.out: Character develops itself in the stream of life.
2022-05-25 13:50:37.050 10165-10165/com.example.lab I/System.out: Johann Wolfgang von Goethe
2022-05-25 13:50:37.121 10165-10165/com.example.lab I/System.out: Set
2022-05-25 13:50:54.003 10165-10225/com.example.lab D/EGL_emulation: eglMakeCurrent: 0xddc05ba0: ver 3 0 (tinfo 0xddc03420)
2022-05-25 13:50:54.009 10165-10225/com.example.lab D/EGL_emulation: eglMakeCurrent: 0xddc05ba0: ver 3 0 (tinfo 0xddc03420)
2022-05-25 13:50:55.652 10165-10165/com.example.lab I/System.out: Getting data
2022-05-25 13:50:55.656 10165-10165/com.example.lab I/System.out: Technological progress has merely provided us with more efficient means for going backwards.
2022-05-25 13:50:55.656 10165-10165/com.example.lab I/System.out: Aldous Huxley
2022-05-25 13:50:55.751 10165-10225/com.example.lab D/EGL_emulation: eglMakeCurrent: 0xddc05ba0: ver 3 0 (tinfo 0xddc03420)
2022-05-25 13:50:55.757 10165-10225/com.example.lab D/EGL_emulation: eglMakeCurrent: 0xddc05ba0: ver 3 0 (tinfo 0xddc03420)
2022-05-25 13:50:55.759 10165-10165/com.example.lab I/System.out: Set

As you can see, in the final line of output, it is able to print "set", but doesn't output either the quote or the author. Any ideas?

1 Answers

Your request is using an asynchronous callback, so the code in your request callback does not run in the order it is written. If you were expecting it to print "Getting Data", "Set", then the quote/author that is not what it is going to do.

What happens instead when you call the code is:

  1. It prints "Getting data"
  2. It starts the API request to get new data
  3. It prints whatever was previously saved in the quote/author fields
  4. The function returns
  5. Some time much later, when the network request is complete new data is actually retrieved and it calls your myRequest code, prints "Set" and updates the saved fields.

Look at the time stamps in your log, the "Set" printout is about 100 ms after the Getting data + author/quote prints.

If you want to reliably process the new data, you have to move all processing to inside the callback. For example:

System.out.println("Getting data");
String myUrl = "https://api.quotable.io/random";

StringRequest myRequest = new StringRequest(Request.Method.GET, myUrl,
        response -> {
            try{
                // Create a JSON object containing information from the API.
                JSONObject object = new JSONObject(response);
                currentQuote = object.getString("content");
                currentQuoteAuthor = object.getString("author");
                System.out.println("Set");
 
                // print the data, put it in a textview, post it to LiveData,
                // etc from here, not outside the callback
                System.out.println(currentQuote);
                System.out.println(currentQuoteAuthor);

            } catch (JSONException e) {
                e.printStackTrace();
            }
        },
        volleyError -> Toast.makeText(MainActivity.this, volleyError.getMessage(), Toast.LENGTH_SHORT).show()
);

// This STARTS the request, but it is a network request so
// it is slow and does not FINISH until some time later in the
// future. When it FINISHES it will call the code in myRequest
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(myRequest);

// The request has NOT been completed yet at this point - if
// you access the fields set inside the request callback they
// will not have been updated yet.

When you call this, it will

  1. Print "Getting data"
  2. Start the API request to get new data
  3. Return from the function
  4. Some time later in the future it will get the new data, print "Set", then print the new quote/author
Related