Execute a Volley request after another one is finished - android

I have two Volley requests. The first request authenticates the user; the second one gets data from the server.
If I send a GET request and the user is not authenticated, I want to fire the first request, authenticate the user and then keep executing the second one once the user is successfully authenticated.

So, the solution is pretty simple. :)
After I learned about callbacks and how them work, I figured out how to do that. So, I implemented a interface that declared the methods I wanted to invoke:
public interface AuthenticationCallback {
public void onLoginSuccess(String result);
public void onLoginError(String result);
}
public interface ResponseCallback {
public void onLoginSuccess(String result);
public void onAuthorizationError(String result);
}
My function:
public void getConversationMessages(final Context context, final String conversationID, final ResponseCallback responseCallback) {
final String url = GET_CONVERSATION_MESSAGES + conversationID;
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
if (responseCallback != null) {
responseCallback.onLoginSuccess(response);
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if (error.networkResponse != null && error.networkResponse.statusCode == HttpURLConnection.HTTP_UNAUTHORIZED){
if (responseCallback != null) {
responseCallback.onAuthorizationError(error.getMessage());
}
}
}
})
{
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Cookie", AppSingleton.getInstance(context).getCookie());
headers.put("Content-Type", "application/json");
return headers;
}
};
AppSingleton.getInstance(context).getRequestQueue().add(stringRequest);
}
}
My Activity:
ServerConnection.getInstance().getConversationMessages(getApplicationContext(), id, new ResponseCallback() {
#Override
public void onLoginSuccess(String result) {
}
#Override
public void onAuthorizationError(String result) {
ServerConnection.getInstance().loginFunction(getApplicationContext(), userID, new AuthenticationCallback() {
#Override
public void onLoginSuccess(String result) {
ServerConnection.getInstance().getConversationMessages(getApplicationContext(), conID, new ResponseCallback() {
#Override
public void onLoginSuccess(String result) {
}
#Override
public void onAuthorizationError(String result) {
}
});
}
#Override
public void onLoginError(String result) {
}
});
}
});
Basically, the code will try to send a GETrequest. If the user is not authenticated, then it will execute the code at onAuthorizationError(), that will authenticate the user. Once the user is successfully authenticate, it will send the GET request again.
I think nesting callbacks like this is not a good practice, but I'll fix it later and update my answer.
If someone have a better way to implement that, please, post another answer!

You can put one volley method inside another, as soon as the first request gets finished it sends the another request.By doing this the data will be sent to the database and the same modified data can be fetched again. The code is as shown below.
StringRequest stringRequest = new StringRequest(Request.Method.POST, "YOUR_FIRST_URL", new Response.Listener < String > () {
#Override
public void onResponse(String response) {
StringRequest stringRequests = new StringRequest(Request.Method.POST, "YOUR_SECOND_URL", new Response.Listener < String > () {
#Override
public void onResponse(String response) {
try {
JSONArray genreArry = new JSONArray(response);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}) {
#Override
protected Map < String, String > getParams() {
Map < String, String > params = new HashMap < String, String > ();
return params;
}
};
int socketTimeouts = 30000;
RetryPolicy policys = new DefaultRetryPolicy(socketTimeouts, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
stringRequests.setRetryPolicy(policys);
RequestQueue requestQueues = Volley.newRequestQueue(context);
requestQueues.add(stringRequests);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}) {
#Override
protected Map < String, String > getParams() {
Map < String, String > params = new HashMap < String, String > ();
return params;
}
};
int socketTimeout = 30000;
RetryPolicy policy = new DefaultRetryPolicy(socketTimeout, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
stringRequest.setRetryPolicy(policy);
RequestQueue requestQueue = Volley.newRequestQueue(context);
requestQueue.add(stringRequest);

Related

Android Volley return value from response

How do I get the response out of onResponse so that I can return it? I have found this but I don't really understand how to implement it for me. How can I return value from function onResponse of Volley?
I hope there is an updated method or something easier that I might have missed
This is my code
public Boolean checkIfPersonExists(Context context, final Person aPerson){
StringRequest postRequest = new StringRequest(Request.Method.POST, USEREXISTS, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d("RESPONSE",response.toString());
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> params = new HashMap<>();
params.put("email",aPerson.getEmail());
params.put("phone",aPerson.getPhone());
return params;
}
};
Volley.newRequestQueue(context).add(postRequest);
return null;
}
As it was mentioned, you need to implement interface and get a callback
Create a new interface like this
public interface GeneralCallbacks {
void VolleyResponse(String data);
}
Implement the interface on your activity class
public class YourActivity implements ScoreboardCallback
{
#Override
public void VolleyResponse(String data)
{
//do stuff with data
}
}
And finally changing your response function to something like this
#Override
public void onResponse(String response) {
((GeneralCallbacks)context).VolleyResponse(response); // This will make a callback to activity.
aPerson.SomeFunction(); // This will call person's function
Log.d("RESPONSE",response.toString());
}

How to use Call Type with EventBus

I am using EventBus to notify Activity/Fragment when I get response from the server. Everything works good so far, but problem arises when I consume two network calls in same Fragment or Activity. The problem is the same method onEvent(String response) get calls for both responses from server. The response of call 1 is different from call 2.
I came up with a solution - I added CallType in NetworkReqest but I can't notify the activity/fragment about the network call since post() takes only one parameter.
Here is the relevant code -
public class NetworkRequest {
EventBus eventBus = EventBus.getDefault();
public void stringParamRequest(String url, final Map<String, String> params,String callType) {
StringRequest jsonObjRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
eventBus.post(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d("volley", "Error: " + error.getMessage());
eventBus.post(error);
}
}) {
#Override
public String getBodyContentType() {
return "application/x-www-form-urlencoded; charset=UTF-8";
}
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> param = params;
return param;
}
};
SkillSchoolApplication.get().addToRequestQueue(jsonObjRequest);
}
public void stringRequest(String url, String callType) {
StringRequest stringRequest = new StringRequest(url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
eventBus.post(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
SkillSchoolApplication.get().addToRequestQueue(stringRequest);
}
}
Method Inside the fragment/activity Here arise the problem when after getting the response from one request i fire another request which is dependent of the respose of the first request
#Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(String response) {
Log.d(TAG, response);
boolean isCourseAvaible = false;
if (!isCourseAvaible) {
isCourseAvaible = true;
List<CoursesDTO> coursesDTOs = AppMgr.coursesMgr(response);
String[] ids = new String[0];
String id;
if (coursesDTOs != null) {
ids = new String[coursesDTOs.size()];
for (int i = 0; i < coursesDTOs.size(); i++) {
ids[i] = coursesDTOs.get(i).getListId();
}
}
id = TextUtils.join(",", ids);
Map<String, String> map = new HashMap<>();
map.put("part", "snippet,contentDetails");
map.put("playlistId", id);
map.put("key", AppConstants.YOUTUBE_KEY);
NetworkRequest networkRequest = new NetworkRequest();
networkRequest.stringParamRequest("some url", map);
} else {
Log.d(TAG, response);
}
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(VolleyError error) {
Log.d(TAG, error.toString());
Toast.makeText(getActivity(), "Something went wrong " + error.toString(), Toast.LENGTH_SHORT).show();
}
How can I differentiate the callType within onEvent(). Some guidance is required. Thanks much.
One option is to wrap the two pieces of data you need into a class and pass that to event bus. Leaving off private members, getters/setters and constructors for brevity.
class NetworkResponse() {
public String callType;
public String response;
}
When you get a response, allocate a NetworkResponse and populate it with the response and the call type and post that to the event bus.
#Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(NetworkResponse networkResponse) {
if(networkResponse.callType.equals(CALL_1)) {
// ...
} else if (networkResponse.callType.equals(CALL_2)) {
// ...
}
}
Serialize the String response to a java bean in the onResponse method, and emit the right object to the views. Activities, Fragments and Views have no need to know about serialization, and besides, your app's performance can improve, since you can modify your code to serialize the data in a background thread.
public void stringRequest(String url, String callType) {
StringRequest stringRequest = new StringRequest(url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
eventBus.post(AppMgr.coursesMgr(response));
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
SkillSchoolApplication.get().addToRequestQueue(stringRequest);
}
Then your first event subscription will look like this:
#Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(List<CoursesDTO> coursesDTOs) {
Log.d(TAG, response);
boolean isCourseAvaible = false;
if (!isCourseAvaible) {
isCourseAvaible = true;
String[] ids = new String[0];
String id;
if (coursesDTOs != null) {
ids = new String[coursesDTOs.size()];
for (int i = 0; i < coursesDTOs.size(); i++) {
ids[i] = coursesDTOs.get(i).getListId();
}
}
id = TextUtils.join(",", ids);
Map<String, String> map = new HashMap<>();
map.put("part", "snippet,contentDetails");
map.put("playlistId", id);
map.put("key", AppConstants.YOUTUBE_KEY);
NetworkRequest networkRequest = new NetworkRequest();
networkRequest.stringParamRequest("some url", map);
} else {
Log.d(TAG, response);
}
}
and you can have a second, different, String subscription. But since you are going to make the second call anyway, it would be best to execute it directly after getting the right answer from the first one.
public class NetworkRequest {
EventBus eventBus = EventBus.getDefault();
public void stringParamRequest(String url, final Map<String, String> params,String callType) {
StringRequest jsonObjRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
eventBus.post(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d("volley", "Error: " + error.getMessage());
eventBus.post(error);
}
}) {
#Override
public String getBodyContentType() {
return "application/x-www-form-urlencoded; charset=UTF-8";
}
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> param = params;
return param;
}
};
SkillSchoolApplication.get().addToRequestQueue(jsonObjRequest);
}
public void stringRequest(String url, String callType) {
StringRequest stringRequest = new StringRequest(url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
List<CoursesDTO> coursesDTOs = AppMgr.coursesMgr(response);
String[] ids = new String[0];
String id;
if (coursesDTOs != null) {
ids = new String[coursesDTOs.size()];
for (int i = 0; i < coursesDTOs.size(); i++) {
ids[i] = coursesDTOs.get(i).getListId();
}
}
id = TextUtils.join(",", ids);
Map<String, String> map = new HashMap<>();
map.put("part", "snippet,contentDetails");
map.put("playlistId", id);
map.put("key", AppConstants.YOUTUBE_KEY);
NetworkRequest networkRequest = new NetworkRequest();
networkRequest.stringParamRequest("some url", map);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
SkillSchoolApplication.get().addToRequestQueue(stringRequest);
}
}
Finally, this two lines
boolean isCourseAvaible = false;
if (!isCourseAvaible) {
are superfluous, is like having no condition.

My adapter is not waiting for my onResponse, how do I fix this?

I am trying to get the number of "replies" or length of a response from the network here is my request below.
public class Replies {
private String questionId;
private VolleySingleton mVolleySingleton;
private RequestQueue mRequestQueue;
public int replies;
private String url;
//Predondition:Place the id of the questions into the constructor
//as well as the url
//Postcondition: counts the number of replies
public Replies(String questionId) {
this.questionId = questionId;
JsonRequestMethod();
}
public void JsonRequestMethod() {
url = "sampleURl"
mVolleySingleton = VolleySingleton.getInstance();
mRequestQueue = mVolleySingleton.getRequestQueue();
JsonArrayRequest request = new JsonArrayRequest(Request.Method.GET,url, (String) null, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
replies=response.length();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
});
mRequestQueue.add(request);
}
public String getReplies() {
return replies+"";
}
}
Also, in my adapter i have in my on bindviewholder this line of code
Replies replies=new Replies(currentSearch.getId());
holder.replies.setText(replies.getReplies());
However, it keeps getting set to 0 because its not waiting for the response, and the response is not 0. How do i fix this?
Maybe you can
public class Replies {
...
private NetWorkFinishListener listener;
void setListener(NetWorkFinishListener listener){
this.listener = listener;
}
public interface NetWorkFinishListener{
void onSuccess(int replies);
void onFailed(VolleyError error);
}
JsonArrayRequest request = new JsonArrayRequest(Request.Method.GET,url, (String) null, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
replies=response.length();
if(listener != null){
listener.onSuccess(replies);
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
if(listener != null){
listener.onFailed(error);
}
}
});
}
And
Replies replies=new Replies(currentSearch.getId());
replies.setListener(new NetWorkFinishListener() {
#Override
public void onSuccess(int replies) {
holder.replies.setText(replies.getReplies());
}
#Override
public void onFailed(VolleyError error) {
// do some thing
}
});
//holder.replies.setText(replies.getReplies());
But there is a bug.
Holder may not be the original.But the listener still run Success().
you can use view.setTag() to judge.

Volley priority doesn't work properly

I have to make two calls with volley. My problem is that I need to be done the first call and then the second. The calls are on a for loop. So I put on the first call Priority.IMMEDIATE and on the second Priority.LOW. But sometimes the second call is done before the first and I doesn't have the data that I need from the first call. What am I missing?
for (int i = 0; i < SiteData.getSites().size(); i++) {
firstCall();
secondCall();
}
the firstCall method
private void firstCall(){
JsonObjectRequest siteDataRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// do something with json
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(membership_id_tag, error.getMessage());
}
})
{
#Override
public Priority getPriority() {
return Priority.IMMEDIATE;
}
};
AppController.getInstance().addToRequestQueue(siteDataRequest, membership_id_tag);
}
the secondCall method
private void secondCall(){
JsonArrayRequest pagesRequest = new JsonArrayRequest(Request.Method.GET, url, null, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
// do something with json
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(membership_page_tag, error.getMessage());
}
})
{
#Override
public Priority getPriority() {
return Priority.LOW;
}
};
AppController.getInstance().addToRequestQueue(pagesRequest, membership_page_tag);
}
Do I have to make the first call on a loop and the second on other?
Try doing the serving call in the response if the first, also the priority might be happening because there are 2 different request queue that are being used.

Volley Request Callback passing the wrong callback response

I've added a callback on the volley request and, I have two request started from 2 different activity. When I perform the first request, then the second return the response of the first..
This is my request and callback:
public static void RequestJsonToServer(Context ctx, final JSONObject params, final VolleyCallback callback){
MySingleVolley.getInstance(ctx).
getRequestQueue();
JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.POST,ctx.getString(R.string.defaultServerRequestUrl),params,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
callback.onSuccess(response);
}
},new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("REQUEST_JSON_TO_SERVER", "Error: " + error);
}
}){
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
return headers;
}
};
MySingleVolley.getInstance(ctx).addToRequestQueue(jsObjRequest);
}
public interface VolleyCallback{
void onSuccess(JSONObject string);
}
And this is one of the two starting request:
Global.RequestJsonToServer(getActivity(), jsonObject, new Global.VolleyCallback() {
#Override
public void onSuccess(JSONObject result) {
Toast.makeText(getActivity(),result.toString(), Toast.LENGTH_LONG).show();
}
});
I hope someone can help me
Thanks
Edit:
I change it like this
Global.RequestJsonToServer(getApplicationContext(), jsonObject, new Global.VolleyCallback() {
#Override
public void onSuccess(JSONObject result) {
Toast.makeText(getApplicationContext(), result.toString(), Toast.LENGTH_LONG).show();
}
#Override
public void onSuccessCustom(JSONObject string) {
}
}, true);
And the other one with false.. But maybe is the wrong way to use it..I would like to have one single callback and reuse it, not switch between two callbacks
MY SOLUTION
I've found my own solution, the problem wasn't in the callback but was in the volley request. The response of each request was cached and i don't know why, it will be return the wrong always the wrong response.
I've just added this before adding request to queue:
jsObjRequest.setShouldCache(false);
This is happening because your callback method is common[onSuccess(...)]why don't you write 2 call backs and based on the condition use the required callback.
To implement it write 2 methods in your interface and pass some sort of flag to choose callback.
Change your interface to this.
public interface VolleyCallback{
void onSuccess(JSONObject string);
void customOnSuccess(JSONObject string);
}
And your method to this
public static void RequestJsonToServer(boolean flag,Context ctx, final JSONObject params, final VolleyCallback callback){
MySingleVolley.getInstance(ctx).
getRequestQueue();
JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.POST,ctx.getString(R.string.defaultServerRequestUrl),params,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
if(flag){
callback.onSuccess(response);
}else{
callback.CustomOnSuccess(response);
}
}
},new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("REQUEST_JSON_TO_SERVER", "Error: " + error);
}
}){
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
return headers;
}
};
MySingleVolley.getInstance(ctx).addToRequestQueue(jsObjRequest);
}
Yes its reusable use onSucces where ever you have only one callback use both when you have more than one.

Categories

Resources