I have written an android library that does network calls to various websites and returns the necessary content. I am using Volley library which has callbacks like onResponse and onFailure. Initially this library was an app and was later changed to an library.
When it was an app I could handle the callbacks easily. Whenever the callback happens I call the required functions from there but now when I import as the library and try to use it the control returns from the library as soon as I call it and the call back is not doing anything.
public void sendForVerification(final String Response, final String Secret, final String Name) {
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
flag = true;
},
new Response.ErrorListener() {
#Override
public void onErrorResponse (VolleyError error){
flag = false;
}
}}) {
#Override
protected Map<String, String> getParams () throws AuthFailureError {
HashMap<String, String> params = new HashMap<>();
params.put("secret", Secret);
params.put("response", Response);
return params;
}
};
requestQueue.add(stringRequest);
}
}
When this code was a part of the app instead of returning the flag value I would call an appropriate function to handle the result. Now whenever I call these functions the value of flag is returned before the callback is done and this is causing some problem.
My question is how can I warp this around a callback so that the app that uses this library will be notified when the network call is done?
You could add your own callback(s) for your library
interface YourCallback<T> {
onResponse(T value);
}
public void sendForVerification(final String Response,final String Secret,final String Name, YourCallback<Boolean> callback){
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
callback.onResponse(true);
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
callback.onResponse(false);
}
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String,String> params = new HashMap<>();
params.put("secret",Secret);
params.put("response",Response);
return params;
}
};
requestQueue.add(stringRequest);
}
boolean flag;
api.sendForVerification("", "", "", new YourCallback<Boolean>() {
#Override
public void onResponse(Boolean value) {
flag = value;
}
});
Volley is asynchronus, so any other upcoming process after you send the request will continue as normal without waiting for a response. That's why your flag value seems like it hasn't changed, because you probably try to access it while the request is still waiting for a response. That's the reason of callback implementations: you take certain actions as soon as you get a response, and you shouldn't try to handle values that will be returned from another method, because they will be returned before they change.
Related
I'm trying to use volley to make a request to this api (specifically the /BusinessTypes/basic endpoint) in order to get a list of types of catering businesses in the UK, but I keep getting an error.
Initially, I tried to retrieve the data during the onCreate method which is what I thought might have been the problem (however, ideally this is what I want to be able to do). After creating a test button on a blank activity and hooking that up to the code that makes the request, I still have the same problem.
I'm targeting API 21 (Not my choice & can't be changed).
This is the code corresponding to the plain activity with a single button that has id "but".
public class BasicActivity extends AppCompatActivity {
final String FSA_EP_T = "http://api.ratings.food.gov.uk/BusinessTypes/basic";
final String FSA_EP_R = "http://api.ratings.food.gov.uk/Regions";
final String FSA_EP_A = "http://api.ratings.food.gov.uk/Authorities/basic";
Button b;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_advanced_search);
b = findViewById(R.id.but);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
doStuff();
}
});
}
private void doStuff() {
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
JsonArrayRequest typeRequest = new JsonArrayRequest(
Request.Method.GET,
FSA_EP_T,
null,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.e("businessType", String.valueOf(response));
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("VolleyErr", "I keep seeing this!!!");
}
}
) {
#Override
public Map<String,String> getHeaders() {
Map<String, String> params = new HashMap<String, String>();
//The api requires me to specify the api version
params.put("x-api-version","2");
params.put("accept", "application/json");
return params;
}
};
typeRequest.setRetryPolicy(new DefaultRetryPolicy(
10000,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(typeRequest);
}
}
After some playing around I finally realised my problem.
The api endpoint I am using returns a json object which contains a json array, not just a single json array like I assumed it would.
I extracted the array I needed using
response.getJSONArray("businessType");
where response is now a JSONObject.
I assumed an error like this would have shown up automatically in my log but it didn't.
For anyone else having similar problems, I recommend adding
Log.e("VolleyError", error.getMessage());
to the onErrorResponse method.
Good day, everyone. Please, I really need an answer to this.
I am new to Android development. I am trying to develop an app meant for broadcast messaging. I have been able to create a database where registered users are stored in a table. However, I lack the idea of what to do next.
Most of the tutorials I have seen teach how to make use of users registered on the PARSE platform. But I wonder if I could be able to lift the users on MySQL database and integrate it with any chat client. Thanks.
Check out the Volley library, it's a library made by Google to make requests.
here you have some explications about Volley. You'll need to import volley library in your project.
you have to create the singleton class given by Google (Here called mySingleton) and to create a request class with code like this one :
public class MyRequest {
private Context context;
private RequestQueue queue;
public MyRequest(Context context, RequestQueue queue) {
this.context = context;
this.queue = queue;
}
public void getArticles(final GetArticlesCallback callback){
String url = "YourScriptUrl";
StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
callback.onSuccess("I will get this string in the activity");
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
callback.onError("erreur : " + error.toString());
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> map = new HashMap<>();
map.put("tag", "postArgument1");
map.put("tag2", "postArgument2");
return map;
}
};
queue.add(request);
}
public interface GetArticlesCallback{
void onSuccess(String success);
void onError(String error);
}
}
And you call this class in your activity :
//queue is a RequestQueue
//request is a Myrequest
queue = VolleySingleton.getInstance(this).getRequestQueue();
request = new MyRequest(this, queue);
request.getArticles(new MyRequest.GetArticlesCallback() {
#Override
public void onSuccess(String success) {
}
#Override
public void onError(String error, String id) {
}
});
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.
I am creating an Android App that will communicate with ReST API . And i want to know how do I provide security to the APIs
Here is my sample API method
#GET
#Path("/count")
public String totalUserCount(){
return "100";
}
and here is my call to api from android
StringRequest stringRequesttoNearby = new StringRequest(
Request.Method.GET,
url,
new Response.Listener<String>() {
#Override
public void onResponse(String responseString) {
//response
}
},
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;
}
};
//add request to queue
Singleton.getInstance().getRequestQueue().add(stringRequesttoNearby);
So I want to know how I can add security to this API call
You could use Oauth1.0a, Oauth2 check out the link
Follow link Secure Api
I'm using google volley for networking in android. I will make a http GET request and need to return a response header value. I found some answers on stack overflow to access the header fields, but don't know how to return it to my calling spot.
Please have a look at my code, I put four numbers in it to explain my problem.
At (1) I can print out the value which I need. Than I've tried to save it in a class attribute (2) and there is no error in the IDE. If I want to return it from there (3), I got a NullPointerException at (4). Maybe its a read before write problem there.
So how can I get the value from (1) to (4)? Thanks a lot!
public class Login {
String phpsessid = null;
public Login() {}
public String getSessionId(Context context) {
RequestQueue queue = Volley.newRequestQueue(context);
StringRequest sr = new StringRequest(Request.Method.GET, "any url",
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
System.out.println(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}) {
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
System.out.println(response.headers.get("Set-Cookie")); (1)
phpsessid = response.headers.get("Set-Cookie"); (2)
return super.parseNetworkResponse(response);
}
};
queue.add(sr);
return phpsessid; (3)
}
}
in main:
Login login = new Login();
String result = login.getSessionId(this.getContext);
System.out.println(result); (4)
When you add a request to the queue, that request is executed asynchronously. This means it is not executed in the same order as you're reading it - it happens on another thread, and will return eventually when it's done.
protected Response<String> parseNetworkResponse(NetworkResponse response) {
System.out.println(response.headers.get("Set-Cookie")); (1)
phpsessid = response.headers.get("Set-Cookie"); (2)
return super.parseNetworkResponse(response);
}
This returns the body of the response - from what I'm reading in your code, it looks like you want to return the value of the "Set-Cookie" header. You can do this like this:
protected Response<String> parseNetworkResponse(NetworkResponse networkResponse) {
String sessionId = response.headers.get("Set-Cookie");
com.android.volley.Response<String> result = com.android.volley.Response.success(sessionId,
HttpHeaderParser.parseCacheHeaders(networkResponse));
return result;
}
This will return the value of the "Set-Cookie" header to your onResponse method:
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
System.out.println(response);
}
}
A better idea may be to pass a success/failure listener in when making your getSessionId call. In this way, you can then easily get access to the result in the calling class:
public void getSessionId(Context context, final Response.Listener<String> successListener, Response.ErrorListener failureListener) {
RequestQueue queue = Volley.newRequestQueue(context); // This should be a singleton!
StringRequest sr = new StringRequest(Request.Method.GET, "any url",
successListener,
failureListener) {
#Override
protected Response<String> parseNetworkResponse(NetworkResponse networkResponse) {
String sessionId = response.headers.get("Set-Cookie");
com.android.volley.Response<String> result = com.android.volley.Response.success(sessionId,
HttpHeaderParser.parseCacheHeaders(networkResponse));
return result;
}
};
queue.add(sr);
}
Edit:
Now, you can call this as follows:
Login login = new Login();
login.getSessionId(this, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// You can access member variables from here.
// This will only get called after the network activity has happened!
phpsessid = response;
// All the work you need to do after your session ID has updated, you can put into a method and call it from here
// In your original example, this would be (4)
onSessionIdUpdated();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// We'll just ignore these for now - you should handle errors though!
}
});
// Anything you put here will happen immediately after the getSessionId call above, and notably *before* onResponse or onErrorResponse is called (ignoring potential race conditions here for now).