I use volley in the Android Activity, and make a request and got the response, but I want to handle the response maybe in an another method,but it won't work, what should i do ?
public class TestActivity extends Activity {
RequestQueue queue;
private String result;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String url = "www.google.com/something/I/need";
queue = Volley.newRequestQueue(this);
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// Do something with the response
Log.i("resp", response);
// I want to do sth with the response out of here
// maybe like this, let result = response
// and see the log at the end of the code
// but it failed, what should I do?
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// Handle error
Log.e("error", error.toString());
}
});
queue.add(stringRequest);
Log.e("result", result);
}
The Volley requests are asynchronous, so the program after sending the request, continues execution without waiting for the answer. So the code that processes the result is inserted into the OnResponse method. For more precise help explain why you would like to log out of the method OnResponse
Think about what you're doing: You're creating a StringRequest, then you add it to the request queue, but then you immediately try to check the result. Obviously, this won't work because the request hasn't been processed yet.
Your response will arrive in the onResponse method, and only then you'll be able to do something with it. You can set result = response here, but you'll only be able to see the value when the onResponse is called which could take some time.
Hope this clarifies things.
Related
I am making Volley GET Requests which will work until I get to a specific activity and then it stops calling the onResponse in the Response.Listener. Here is my Volley Request method:
public static void stringReqGet(String url, final VolleyCallback callback){
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
System.out.println("In VolleyRequest onResponse(): " + response);
callback.onSuccess(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("Error" ,error.getMessage());
}
});
System.out.println("Adding request to queue: " + stringRequest.toString());
Utilities.getInstance().addToRequestQueue(stringRequest);
}
Here's how I'm making the request in the activity in question:
CourseUtil.loadCourse(courseID, new VolleyCallback() {
#Override
public void onSuccess(String response) {
System.out.println("JSON Success");
courseJSON = response;
}
});
and in CourseUtil class:
public static void loadCourse(int courseID, VolleyCallback callback){
VolleyRequest.stringReqGet(Const.URL_COURSE + courseID,callback);
}
I'm getting no Volley errors just seemingly no response. Here are my (truncated) logs:
I/System.out: Adding request to queue: [ ] http://server/courses/267267267 0xebb503b0 NORMAL null
I/System.out: In VolleyRequest onResponse(): *Correct Response Object*
.
.
.
I/System.out: 267267267 <-- Same course ID used in first request
I/System.out: Adding request to queue: [ ] http://server/courses/267267267 0xebb503b0 NORMAL null
*onResponse never called*
The first time this request is made you can see that the onResponse() method is called and it returns the correct object. The signature of this 'correct' request is the exact same as the one above. The next time that exact request is made the onResponse is never called and I get no error.
I've looked at other posts on here but none of their solutions fixed the problem I am having and no error makes it hard to know what's going on.
Any help would be greatly appreciated.
Put:
System.out.println("JSON Success");
courseJSON = response;
into a separate method outside the callback and it works now. Not sure why...
I know there are lots of tutorials for OkHttp, but basically all of them do something different in the onResponse method and most don't bother to explain why. Some check for if (response.isSuccessful), some surround it with try/catch, some don't do any of this at all.
This is my example project. What is the proper way to handle the onResponse method?
public class MainActivity extends AppCompatActivity {
private TextView textViewResult;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textViewResult = findViewById(R.id.text_view_result);
OkHttpClient client = new OkHttpClient();
String url = "https://reqres.in/api/users?page=2";
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
final String myResponse = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
textViewResult.setText(myResponse);
}
});
}
});
}
}
Update
onResponse of okhttp runs on background thread. So, yes, it's necessary to do MainActivity.this.runOnUiThread(...).
Original answer
onResponse callback already runs on ui thread AFAIK. So, you don't actually need to do MainActivity.this.runOnUiThread(...).
And everyone's onResponse is different because everyone has different needs. Use try/catch if your operations in onResponse might give error and you don't want it to crash.
For some network requests you may need to check if response is successful for other you may not. It all depends on use cases. Do what works for you best.
I'd suggest you surround your code in onResponse in a try/catch block because the user might close the app before the network request is finished. And when you set the textview text in onResponse it will crash because the activity and that textview doesn't exist anymore.
Adding to the answer from rafid. There are basically three cases you want to check.
response.isSuccessful() => status code between 200 and 300
response.code() => to manually check after response is not successful
onFailure() => Network error or parsing error etc.
Ideally your callback would handle those cases something like
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
// network error or parsing error
}
#Override
public void onResponse(Call call, Response response) {
if (response.isSuccessful()) {
// do stuff all good
} else {
// handle different cases for different status codes or dump them all here
}
}
});
The reason you need a try-catch is because OkHttp is trying to parse the response. This is the case for example for response.errorBody().string();. Another case would be if your Callback<T> has actually a type parameter. Again OkHttp will try to parse the response to that type. If it fails it will result in a callback onto the onFailure method.
I think you need to make sure you know the legal response from the request, like an json or File. if it's just a json, use like below:
#Override
public void onResponse(Call call, Response response) throws IOException {
final String myResponse = response.body().string();
if (response.isSuccessful() && !TextUtils.isEmpty(myResponse)) {
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
textViewResult.setText(myResponse);
}
});
}
}
Edit: To be more clear.
Callback is running in mainThread so there is no need to call runOnUiThread.
If response is not successful you can try to parse error body as below. If response is successful you can parse with Gson as i show.
String message = "";
if (response.errorBody() != null) {
try {
message = response.errorBody().string();
} catch (IOException ignored) {
Log.e("OkHttp IOException", "error while parsing response");
}
Log.d("Error Message", message);
}
I recommend you to use Gson Library. First you should create your pojo class. You can use http://www.jsonschema2pojo.org/ to create your pojo class. Then you can parse body like below
Gson gson = new Gson();
MyPojo myPojo = gson.fromJson(response.body().charStream(), MyPojo.class);
I'm trying to use Volley to execute multiple HTTP request where each one of them relies on the result of the previous one, what is the best option as a design?
1-Firing the next request in the onResponse callback of the previous request?
2-Writing some coordinator class that have callbacks that get called in the onResponse method of a request and fires the next request
skeleton code for the second option
coodrinator = new Coordinator();
JsonObjectRequest firstRequest = new JSONObjectRequest(Request.Method.GET,firstURL),new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
//handle the responsee
coordinator.onFirstRequestRecieved();
}
},
errorListener);
private void doSecondRequest(){
JsonObjectRequest secondRequest = new JSONObjectRequest(Request.Method.GET,secondURL),new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
//handle the responsee
coordinator.onSecondRequestRecieved();
}
},
errorListener);
}
private class Coordinator{
public void onFirstReequestRecieved(){
doSecondRequest();
}
public void onSecondRequestRecieved(){
//do Something
}
}
If first request response parameters are needed for making second request and so on then you can go for synchronous way. That can be achieved by making second request in onResponse on First request can there is no good or bad practise for it.
The thing is volley is asynchronous and request what is added in the queue execute without depending on other request and we are going to make it synchronous request and it can be achieved by many ways seeing your requirement.
I want to send two different requests and handle two different responses in one Activity using Volley library.
My activity implements onResponseListener, so i have only one onResponse method and both responses are handled here. As they are completely same in structure i cant tell which is which.
How can i tell from which request i have received the response so i can handle them differently? Is there a way to "tag" a request or something like that?
I could set some kind of check variable, e.g. boolean firstRequestIsSent when i send the request, and then check it in the onResponse method, but its a pretty ugly solution.
Many thanks
Instead of implementing onResponse as part of the class, you can instantiate a new Response.Listener with the request. This way you will have a separate listener for each request.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener() {
#Override
public void onResponse(String response) {
// individual response here
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// error here
}
});
I've seen answer to both of these questions, however, when I tried to put them together, I couldn't make it work. The problem itself is pretty simple: I want to get a string from one site and use it in a post request. That means I can only make the post request after I've finished parsing the GET request. The main ideas I'm using are these ones:
How to return response header field to main method using Google Volley for HTTP GET request in Android / Java?
Can I do a synchronous request with volley?
However the synchronous request is blocked and doesn't go on, and the first one is Async.
I believe this to be a simple thing to do, but still, I haven't be able to do it...
Thanks for any help!
Why not do something like this:
// send first request
requestQueue.add(firstRequest, null, new Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// ** code to parse response **
// send second request
requestQueue.add(secondRequest, null, new Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// ** code to parse response **
}
}, new ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// ** code to handle errors **
}
}));
}
}, new ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// ** code to handle errors **
}
}));