I need to call an api to get a json data using android volly. I have a method implemented inside class A to call the get request as shown
class A{
public static String getList(Context context,String url)
{
final String[] result = new String[1];
JsonArrayRequest req = new JsonArrayRequest(url,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.e("response",response.toString());
result[0] =response.toString();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("responseerror",error.toString());
result[0] =error.toString();
}
});
MySingleton.getInstance(context).addToRequestQueue(req);
return result[0];
}
}
Inside class B i am accesing this method
class B {
String responce= A.getList(activity,url);
}
Here i can pass the context and url to get json data. But the problem is getList() method ruturs result even before it gets any response from the server. The app have more than one class which needs to call get request. If i will use this code snippet inside every such class then it will be against DRY principle. So what is the proper procudure to follow in this scenario?
Use an interface like below.
class A {
private final WeakReference<ResponseListener> responseListenerWeakRef;
public A(ResponseListener responseListener) {
responseListenerWeakRef = new WeakReference<ResponseListener>(responseListener);
}
public String getList(Context context, String url) {
JsonArrayRequest req = new JsonArrayRequest(url,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.e("response",response.toString());
if (responseListener!=null && responseListener.get()!=null) {
responseListener.get().onResponse(response.toString());
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("responseerror",error.toString());
if (responseListener!=null && responseListener.get()!=null) {
responseListener.get().onResponse(error.toString());
}
}
}
);
MySingleton.getInstance(context).addToRequestQueue(req);
}
public interface ResponseListener {
void onResponse(String response);
}
}
class B implements A.ResponseListener {
private void makeApiCall() {
new A(this).getList(activity, url);
}
#Override
public void onResponse(String response) {
// Do something with the response.
}
}
Related
I'm using getConnection method in my program and I want to restore the response in a variable like "String result " in-order to use in another class, but I don't know how I must change the method. Does anyone have an idea?.
public class Webservice {
public static void getConnection(Context context, String url){
RequestQueue queue = Volley.newRequestQueue(context);
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.i("TEST", "Response is: "+ response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.i("TEST","That didn't work!");
}
});
queue.add(stringRequest);
}
}
You can create a variable in Application class and use it throughout your application like this
public class App extends android.app.Application {
private static App instance;
public static String resultResponse;
public static App getInstance() {
return instance;
}
#Override
public void onCreate() {
super.onCreate();
instance = this;
}
}
Then when you get the response save it like this
public class Webservice {
public static void getConnection(Context context, String url){
RequestQueue queue = Volley.newRequestQueue(context);
StringRequest stringRequest = new StringRequest(Request.Method.GET,
url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.i("TEST", "Response is: "+ response);
App.getInstance().resultResponse = response;
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.i("TEST","That didn't work!");
}
});
queue.add(stringRequest);
}
}
Add
android:name = ".App"
in Application in your manifest.
Now Use
App.getInstance().resultResponse
where ever you want through out your Application.
You can use interface having return type String in onResponse method and implement this interface in your required class get String response.
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.
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.
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.
I want to send a POST request to my server, and there is no expected data for the result (just HTTP status code - standard behavior). How can I do that ?
(abstract base Request class (Volley) wants a result type)
try {
mRequest =
new XXXXXX(
Request.Method.POST,
url,
null, null,
new Response.Listener() {
#Override
public void onResponse() {
// ok
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError e) {
// ko
}
},
null
);
return mRestCoreVolley.addToRequestQueue(mRequest);
} catch (Exception e) {
// error
}
You could try something like in the code below for the response listener:
new Response.Listener<Void>() {
#Override
public void onResponse(Void response) {
}
}
I guess your code is right. You can use a String like:
RequestQueue rq = Volley.newRequestQueue(this);
StringRequest postReq = new StringRequest(Request.Method.POST,
your_url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// do nothing
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// Handle error
}
}) ;
Hope it helps you!