I have a following method, which submits http request using Volley:
private boolean SaveInformationToServer(Information information)
{
RequestQueue queue = Volley.newRequestQueue(this);
StringRequest stringRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try{
return true;
}
catch (Exception ex){
return false;
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
return false;
}
});
queue.add(stringRequest);
}
I require this method to return either true or false but currently it's giving error void method cannot return a value. I tried a variable, then I got cannot refer to the non-final local variable inside an inner class.
How can I make this method return a boolean value to its caller?
The return type of onResponse is void plus it's a function of an anonymous class so you can't return value from anonymous class to your caller of volley request.
You can create your function can call them on volley response and put your code to execute the result instead of keeping a flag, this will keep your code more structural and readable(you can also set you flags in your onSuccess).
void onSuccess(String response){
// do what you want to do
}
void onError(VolleyError error){
// do what you want to do
}
private void SaveInformationToServer(Information information)
{
RequestQueue queue = Volley.newRequestQueue(this);
StringRequest stringRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
onSuccess(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
onError(error);
}
});
queue.add(stringRequest);
}
Related
My API is returning integer in JSON format I tried using jasonobject request , Jason array, and Jason string through volley but was still unable to receive an integer in response.
Note: I am getting the correct response in postman
String url = static_ip.ip+"/api/Notification/GetDayWiseNotification";
Log.d("url",url);
try {
RequestQueue requestQueue= Volley.newRequestQueue(Collector_screen.this);
JsonObjectRequest request= new JsonObjectRequest(
Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d("Onresponse","hello");
try{
int numb= Integer.parseInt(String.valueOf(response));
Log.d("lala", String.valueOf(numb));
donerequest.setText(String.valueOf(numb));
}
catch (Exception e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}
);
request.setRetryPolicy(new DefaultRetryPolicy(5000,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(request);
}`enter code here`
catch(Exception ea){
String err = ea.getMessage().toString();
}
I am trying to get my volley JsonObjectRequest working. When calling the getById() meth, onResponse() does not get called. I already have a working post request. So the connection parameters are correct. I do not get any error response or helpfull responses in LogCat.
I created a test class in order to isolate the getById() method.
public class Test {
Customer customer;
public Customer getById(int id) {
Log.i("CustomerDAO getById", "getById called");
String urlJsonObj = "http://192.168.0.39:3000/Customers/" + id;
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, urlJsonObj, null, new Response.Listener < JSONObject > () {
#Override
public void onResponse(JSONObject response) {
try {
// Parsing json object response
// response will be a json object
customer = new Customer(response.getInt("customernumber"), response.getString("name"),
response.getString("lastname"), response.getString("phonenumber"),
response.getInt("addressid"), response.getString("password"));
} catch (JSONException e) {
Log.e("JSON Exception:", e.toString());
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("GetByIdErrorResponse", error.toString());
}
});
AppController.getInstance().addToRequestQueue(request);
return customer;
}
}
This is the singleton RequestQueue class.
public class AppController extends Application {
public static final String TAG = AppController.class
.getSimpleName();
private RequestQueue mRequestQueue;
private static AppController mInstance;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
public static synchronized AppController getInstance() {
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
Log.i("RequestQueue= ", mRequestQueue.toString());
}
return mRequestQueue;
}
}
This is how I call the getById() method
Test test = new Test();
Entities.Customer check = test.getById(1);
There are a few mistakes in your code. Since volley is an asynchronous networking library, you can't return the result from the network as you have done. You are initializing your Customer model class inside OnResponse and returning it from outside of it.
So what will be happening when you perform this operation is
Creates Request -> Adds to Request Queue -> getById() method returns null
The return statement, at last, won't wait till the response arrives. You'll be getting null every time. So what you have to do is to implement a custom callback when the API returns a result or error.
Create an interface for inside Test class for handling API response.
interface APICallback {
void onSuccess(Customer customer);
void onError(String error);
}
Pass these interface implementation to the getById() method along with id
public void getById(int id,APICallback callback) {
....
}
call methods on result
#Override
public void onResponse(JSONObject response) {
try {
// Parsing json object response
// response will be a json object
Customer customer = new Customer(response.getInt("customernumber"), response.getString("name"),
response.getString("lastname"), response.getString("phonenumber"),
response.getInt("addressid"), response.getString("password"));
callback.onSuccess(customer);
} catch (JSONException e) {
Log.e("JSON Exception:", e.toString());
}
}
#Override
public void onErrorResponse(VolleyError error) {
Log.e("GetByIdErrorResponse", error.toString());
callback.onError(error.toString());
}
and now you can call getById() as follows
Test test = new Test();
test.getById(1, new Test.APICallback() {
#Override
public void onSuccess(Customer customer) {
}
#Override
public void onError(String error) {
}
});
I'm trying to do a setText() on a Textview (already instantiate in the onCreate()) called by a Handler and using the ruiOnUiTread() but I have a nullPointerException on the Textview.
Where can the problem come from?
I saw in the debug that the instance of the activity was not the same between the instantiation and the setText() while I do not change activity but impossible to instantiate it in the same place as the setText().
private TextView ambianceTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ambianceTextView = findViewById(R.id.valeur_ambiance);
StarterKillerPidroid.getInstance().startApp();
}
private final Runnable retrieveData = new Runnable() {
public void run() {
try {
setText();
} catch (Exception e) {
e.printStackTrace();
}
handlerRecup.postDelayed(retrieveData, 1000);
}
};
public void setText(){
runOnUiThread(new Runnable() {
#Override
public void run() {
ambianceTextView.setText("test");
}
});
}
public void doAfterLogin() {
handlerRecup.postDelayed(retrieveData, 10000);
}
the runnable is started by a function called by a callback of an http request with Volley
public class StarterKillerPidroid {
void startApp() {
//Sending a request
PostmanPidroid.getInstance().login();
}
public void ackLogin(Boolean isValid) {
if (isValid) {
ActivityMain.getInstance().doAfterLogin();
} else {
PostmanPidroid.getInstance().login();
}
}
}
The class Postman :
public class Postman {
public void login(){
// Parameters
String email = "test#tes";
String password = "test";
// Encoding the request with parameters
JsonObjectRequest request = EncoderDecoderPidroid.getInstance()
.encodeRequestLogin(email, password);
// Sending the request
sendRequest(request);
}
void sendRequest(StringRequest message){
// Creating the queu if it's not create
if (queue == null) {
queue = Volley.newRequestQueue(context);
}
// Adding the request to the queue
queue.add(message);
}
}
When a success response is received, this callback is called :
private Response.Listener<JSONObject> callbackLogin =
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
...
StarterKillerPidroid.getInstance().ackLogin(true);
}
};
Basically, this kind of problem is due to the instance. It may be possible that your textview instance is not initialized. One more thing using handler directly for updating UI thread is not a good idea. Instead of directly updating Ui with handler you should use FunctionalInterface for doing this.
FunctionalInterface is a good approach for such cases.
A functional interface is an interface that contains only one abstract method. They can have only one functionality to exhibit. From Java 8 onwards, lambda expressions can be used to represent the instance of a functional interface. ... Runnable, ActionListener, Comparable are some of the examples of functional interfaces.
Java has a predefined FunctionalInterface Callable. It goes something like this
public static void doDid(final Callable<Void> callable) {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
try {
callable.call();
handler.postDelayed(this, every * repeattime);
} catch (Exception e) {
e.printStackTrace();
}
}
}, every * tempvalue);
}
and use this for updating UI in this way
doDid(new Callable<Void>() {
#Override
public Void call() {
textView.setText("Your text");
return null;
}
});
There is one open-source library available for Android which works like a charm is such cases called Predictor. You can download it from here and import in your project. You can also contribute in this project for saving many developers life.
Do you wanna see how predictor can do this?
Predictor.every(3).second().doDid(new Job<Void>() {
#Override
public Void run() {
textView.setText("Your text");
return null;
}
});
What can you do with predictor?
Predictor gives you several ways of handling multithreading some of them are as follows:
Predictor.every(3).second().doDid(something());
Predictor.every(5).minutes().doDid(something());
Predictor.every().hour().doDid(something());
Predictor.every().week().doDid(something());
Predictor.every().month().doDid(something());
and many more...
Try this way:
private final Runnable retrieveData = new Runnable() {
public void run() {
try {
ambianceTextView = (TextView) findViewById(R.id.valeur_ambiance);
setText();
} catch (Exception e) {
e.printStackTrace();
}
handlerRecup.postDelayed(retrieveData, 1000);
}
};
I have a problem where i am unable to return a string from this method. I was unsuccessful when I tried creating a new variable outside the Response.Listener. This is probably very simple but how do I go about returning a string from this method. The string I want to return is the 'featured_img_url' string.
public String secondServiceCall(String featuredmedia){
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
"http://www.gadgetsinnepal.com/wp-json/wp/v2/media/"+featuredmedia, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject nested_response) {
try {
JSONObject guilld = nested_response.getJSONObject("guid");
String featured_img_url = guilld.getString("rendered");
Toast.makeText(getApplicationContext(),"IMAGE :" + featured_img_url,Toast.LENGTH_LONG).show();
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(),
"ERROR "+error.getMessage(), Toast.LENGTH_LONG).show();
}
});
MySingleton.getInstance(getApplicationContext()).addToRequestQueue(jsonObjReq);
return featured_img_url;
}
update your code to:
String featured_img_url = null;
public String secondServiceCall(String featuredmedia){
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
"http://www.gadgetsinnepal.com/wp-json/wp/v2/media/"+featuredmedia, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject nested_response) {
try {
JSONObject guilld = nested_response.getJSONObject("guid");
featured_img_url = guilld.getString("rendered");
Toast.makeText(getApplicationContext(),"IMAGE :" + featured_img_url,Toast.LENGTH_LONG).show();
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(),
"ERROR "+error.getMessage(), Toast.LENGTH_LONG).show();
}
});
MySingleton.getInstance(getApplicationContext()).addToRequestQueue(jsonObjReq);
return featured_img_url;
}
Here, you should simply pass the instance that call this methods to execute the methods from the response.
So change the methods to :
public void secondServiceCall(String featuredmedia, final MyClass caller){
Note that this will return nothing. And the caller instance need to be final to be used in the inner class JsonObjectRequest.
and in the response, you need to pass the value to the instance of MyClass. So add a method in MyClass
public void setFeatureImgUrl(String featuredImgUrl){ ... }
and you just need to call this in the response.
public void onResponse(JSONObject nested_response) {
...
caller.setFeatureImgUrl(feature_img_url);
...
}
Note : This could be done with an Observer pattern but I know that some people doesn't like it. I could add an example of it if needed.
Something bad is happening when using Volley to treat a large response:
String url = AppHelper.DOMAIN + "/service/pages/profile_update.json";
this.infoTextView.setText(getString(R.string.profile_info_updating));
final StringRequest stringRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject json = new JSONObject(response);
if (json.getBoolean("success")) {
// manage JSON object here
} else {
Toast.makeText(ProfileActivity.this,
getString(R.string.connection_problem_server),
Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
ProfileActivity.this.infoTextView.setText(
getString(R.string.profile_info_updating_error));
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
ProfileActivity.this.infoTextView.setText(
getString(R.string.profile_info_updating_error));
if (error.networkResponse != null && error.networkResponse.statusCode == 401) {
Toast.makeText(ProfileActivity.this,
getString(R.string.connection_problem_permission),
Toast.LENGTH_LONG).show();
}
new android.os.Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (ProfileActivity.this.swipeRefreshLayout != null) {
ProfileActivity.this.swipeRefreshLayout.setRefreshing(false);
}
}
}, 1000);
error.printStackTrace();
}
}) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("auth_token", ProfileActivity.this.defaultUser.getAuthenticationToken());
return params;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.putAll(super.getHeaders());
params.put("Accept-Encoding", "gzip,deflate");
return params;
}
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
StringBuilder output = new StringBuilder();
try {
GZIPInputStream gStream = new GZIPInputStream(new ByteArrayInputStream(response.data));
InputStreamReader reader = new InputStreamReader(gStream);
BufferedReader in = new BufferedReader(reader, 16384);
String read;
while ((read = in.readLine()) != null) {
output.append(read).append("\n");
}
reader.close();
in.close();
gStream.close();
} catch (IOException error) {
error.printStackTrace();
return Response.error(new ParseError());
}
return Response.success(output.toString(), HttpHeaderParser.parseCacheHeaders(response));
}
};
stringRequest.setRetryPolicy(new RetryPolicy() {
#Override
public int getCurrentTimeout() {
// 40 seconds
return 40000;
}
#Override
public int getCurrentRetryCount() {
return DefaultRetryPolicy.DEFAULT_MAX_RETRIES;
}
#Override
public void retry(VolleyError error) throws VolleyError {
throw error;
}
});
Volley.newRequestQueue(this).add(stringRequest);
this code block the main thread, freezing the application.
Additionally, I set some header values to allow gzip response and a code to handle the data. But it is not the piece that make the undesired behavior. The application freeze only when onResponse(String response) starts.
What can I do to avoid this?
onResponse and onErrorResponse is called on UI thread hence any heavy operation done inside these methods will make you application less responsive. I guess you are trying to parse the response in onResponse() which is incorrect.
You have to move to parsing logic to parseNetworkResponse since this
is the method which is called in background thread. Refer the below link for more details :
https://developer.android.com/training/volley/request-custom.html
If it help someone , try to create a new thread in a method inside onResponse , inside that thread execute your parsing data. I hope the answer works for you