Volley - POST/GET parameters
Asked Answered
H

8

88

I saw Google IO 2013 session about Volley and I'm considering switching to volley. Does Volley support adding POST/GET parameters to request? If yes, how can I do it?

Heathcote answered 18/5, 2013 at 15:41 Comment(4)
I didn't see the whole keynote, but I'm pretty sure the GET should be doable just by adding the parameters to the URL (eg. http://example.com?param1=val1&param2=val2)Coben
There seems to be no documentation yet, but you can check the source here android.googlesource.com/platform/frameworks/volley/+/masterObstetrics
@JJ56 - Right, but what about POST parameters? I saw source code but didn't find anything related to POST parameters.Heathcote
I feel ashamed to say this. But, If you get here asking why your request doesn't have a body on your server, make sure you're using POST/PUT method. Guess I'm just tired. Hope this comment helps anybody or helps me feel betterPresident
J
65

In your Request class (that extends Request), override the getParams() method. You would do the same for headers, just override getHeaders().

If you look at PostWithBody class in TestRequest.java in Volley tests, you'll find an example. It goes something like this

public class LoginRequest extends Request<String> {

    // ... other methods go here

    private Map<String, String> mParams;

    public LoginRequest(String param1, String param2, Listener<String> listener, ErrorListener errorListener) {
        super(Method.POST, "http://test.url", errorListener);
        mListener = listener;
        mParams = new HashMap<String, String>();
        mParams.put("paramOne", param1);
        mParams.put("paramTwo", param2);

    }

    @Override
    public Map<String, String> getParams() {
        return mParams;
    }
}

Evan Charlton was kind enough to make a quick example project to show us how to use volley. https://github.com/evancharlton/folly/

Jongjongleur answered 19/5, 2013 at 21:0 Comment(10)
Notice that the getParams is only called (by default) in a POST or PUT request, but not in a GET request. See Ogre_BGR's answerInterblend
Can't believe I never noticed that until nowJongjongleur
@AfzalivE, any idea about how to sign API request with OAuth when using above code?Amphicoelous
@BipinVayalu If you are connecting to Google API you should be able to use com.android.volley.AndroidAuthenticatorDichroscope
You forgot to instantiate mParams.Gasometer
Lol, probably because I was really excited to answer this question. Fixed.Jongjongleur
It won't work if you need to pass the same key with multiple values, like id=1&id=2&id=3. To do it you need to use com.google.common.collect.Multimap and Override the getBody method instead of the getParams method.Subduct
@ItaiHanski any idea how to get response code to a post request in which paramters are also passed?Waldenses
@Harsha Ognyan's answer covers thatJongjongleur
why "cannot resolve symbol map"? please help, thanksBobbyebobbysocks
M
92

For the GET parameters there are two alternatives:

First: As suggested in a comment bellow the question you can just use String and replace the parameters placeholders with their values like:

String uri = String.format("http://somesite.com/some_endpoint.php?param1=%1$s&param2=%2$s",
                           num1,
                           num2);

StringRequest myReq = new StringRequest(Method.GET,
                                        uri,
                                        createMyReqSuccessListener(),
                                        createMyReqErrorListener());
queue.add(myReq);

where num1 and num2 are String variables that contain your values.

Second: If you are using newer external HttpClient (4.2.x for example) you can use URIBuilder to build your Uri. Advantage is that if your uri string already has parameters in it it will be easier to pass it to the URIBuilder and then use ub.setQuery(URLEncodedUtils.format(getGetParams(), "UTF-8")); to add your additional parameters. That way you will not bother to check if "?" is already added to the uri or to miss some & thus eliminating a source for potential errors.

For the POST parameters probably sometimes will be easier than the accepted answer to do it like:

StringRequest myReq = new StringRequest(Method.POST,
                                        "http://somesite.com/some_endpoint.php",
                                        createMyReqSuccessListener(),
                                        createMyReqErrorListener()) {

    protected Map<String, String> getParams() throws com.android.volley.AuthFailureError {
        Map<String, String> params = new HashMap<String, String>();
        params.put("param1", num1);
        params.put("param2", num2);
        return params;
    };
};
queue.add(myReq);

e.g. to just override the getParams() method.

You can find a working example (along with many other basic Volley examples) in the Andorid Volley Examples project.

Minyan answered 28/5, 2013 at 15:25 Comment(12)
I've followed your examples of Volley. So far it's the most helpful Volly code, but I've an issues in JsonObjectRequest. I got the old response in createMyReqSuccessListener until I reinstall it again. Is volley store data in cache? Please suggest a way to do this.Ifill
Only images are cached. Please check if there is some proxy is intercepting your requests. If the requests has exactly the same URL and it is possible that the proxy is simply returning the first result.Minyan
May be you are right. But how to solve that? Is putting "header("Cache-Control: no-cache"); in the php file.." this line will help?Ifill
There is a plugin for Firefox called "HTTP resource test" that allows you to send requests agains web server. It is quite useful for testing cases like this. Just enter your URL (and POST parameters if any) and see what is the response of the server for multiple consecutive requests. If again you get the same response result is most probably cached. In that case you may examine the returned headers to check if there are proxy headers. About the "no-cache" - yes, it should work.Minyan
I've checked it in "HTTP resource test" add on, I can see new response every time I post the url. So the problem is in the app, probably the structure I'm following to call the volley request. As I said reinstalling the app does the work. I've also put the "no-cache" header to api file.Ifill
I suggest that you open separate question so others can join and help.Please provide info what stack are you using HURL or HttpClient, also the android version that are you testing against. Please, put a link to the new question here so people can follow the discussion.Minyan
Sorry for late replying. I found that the problem is with Genymotion, it's working fine in avd and in Nexus 7. Thanks!Ifill
Any idea why volley does not call getParams() for GET request? Is there some specification restriction? I would appreciate if I does not have to manually construct and escape URI. Parse/prepare parameters in getParams() method seems logical to me.Ingold
@Ogre_BGR, What the difference between Method.GET and Method.POST?, I'm using only Method.GET even for sending parms to the server, Is it bad?Laudable
@Laudable Probably you will get a lot better answers if you ask this as new question, but in short: POST request allows you to send files and other bigger data that will not fit in GET request. Also there is a security risk when using GET request because the URL may get logged on the server thus exposing sensitive data.Minyan
i still do not "GET" how have you made the String uri, can i not just append the values of param1 and param2? is it necessary to provide the other parameter like num1 and num2 still?Partheniaparthenocarpy
@Ogre_BGR: Are the parameters encoded automatically?Trona
J
65

In your Request class (that extends Request), override the getParams() method. You would do the same for headers, just override getHeaders().

If you look at PostWithBody class in TestRequest.java in Volley tests, you'll find an example. It goes something like this

public class LoginRequest extends Request<String> {

    // ... other methods go here

    private Map<String, String> mParams;

    public LoginRequest(String param1, String param2, Listener<String> listener, ErrorListener errorListener) {
        super(Method.POST, "http://test.url", errorListener);
        mListener = listener;
        mParams = new HashMap<String, String>();
        mParams.put("paramOne", param1);
        mParams.put("paramTwo", param2);

    }

    @Override
    public Map<String, String> getParams() {
        return mParams;
    }
}

Evan Charlton was kind enough to make a quick example project to show us how to use volley. https://github.com/evancharlton/folly/

Jongjongleur answered 19/5, 2013 at 21:0 Comment(10)
Notice that the getParams is only called (by default) in a POST or PUT request, but not in a GET request. See Ogre_BGR's answerInterblend
Can't believe I never noticed that until nowJongjongleur
@AfzalivE, any idea about how to sign API request with OAuth when using above code?Amphicoelous
@BipinVayalu If you are connecting to Google API you should be able to use com.android.volley.AndroidAuthenticatorDichroscope
You forgot to instantiate mParams.Gasometer
Lol, probably because I was really excited to answer this question. Fixed.Jongjongleur
It won't work if you need to pass the same key with multiple values, like id=1&id=2&id=3. To do it you need to use com.google.common.collect.Multimap and Override the getBody method instead of the getParams method.Subduct
@ItaiHanski any idea how to get response code to a post request in which paramters are also passed?Waldenses
@Harsha Ognyan's answer covers thatJongjongleur
why "cannot resolve symbol map"? please help, thanksBobbyebobbysocks
F
23

CustomRequest is a way to solve the Volley's JSONObjectRequest can't post parameters like the StringRequest

here is the helper class which allow to add params:

    import java.io.UnsupportedEncodingException;
    import java.util.Map;    
    import org.json.JSONException;
    import org.json.JSONObject;    
    import com.android.volley.NetworkResponse;
    import com.android.volley.ParseError;
    import com.android.volley.Request;
    import com.android.volley.Response;
    import com.android.volley.Response.ErrorListener;
    import com.android.volley.Response.Listener;
    import com.android.volley.toolbox.HttpHeaderParser;

    public class CustomRequest extends Request<JSONObject> {

    private Listener<JSONObject> listener;
    private Map<String, String> params;

    public CustomRequest(String url, Map<String, String> params,
            Listener<JSONObject> reponseListener, ErrorListener errorListener) {
        super(Method.GET, url, errorListener);
        this.listener = reponseListener;
        this.params = params;
    }

    public CustomRequest(int method, String url, Map<String, String> params,
            Listener<JSONObject> reponseListener, ErrorListener errorListener) {
        super(method, url, errorListener);
        this.listener = reponseListener;
        this.params = params;
    }

    protected Map<String, String> getParams()
            throws com.android.volley.AuthFailureError {
        return params;
    };

    @Override
    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
        try {
            String jsonString = new String(response.data,
                    HttpHeaderParser.parseCharset(response.headers));
            return Response.success(new JSONObject(jsonString),
                    HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (JSONException je) {
            return Response.error(new ParseError(je));
        }
    }

    @Override
    protected void deliverResponse(JSONObject response) {
        // TODO Auto-generated method stub
        listener.onResponse(response);
    }

}

thanks to Greenchiu

Freidafreight answered 13/8, 2013 at 10:49 Comment(3)
Thanks alot, I was searching for hours before I get this solution, It's so weird that JSONObjectReuqest getParams() function overriding is not working.Decalcomania
@MohammadWalid FYI read this #16903216 and try to use retrofit! both volley and retrofit can be used with okhttp!Freidafreight
I tried this solution, but didn't work for me. getParams() is not called.Ambi
M
10

This helper class manages parameters for GET and POST requests:

import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.Map;    

import org.json.JSONException;
import org.json.JSONObject;

import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.HttpHeaderParser;

public class CustomRequest extends Request<JSONObject> {
    private int mMethod;
    private String mUrl;
    private Map<String, String> mParams;
    private Listener<JSONObject> mListener;

    public CustomRequest(int method, String url, Map<String, String> params,
            Listener<JSONObject> reponseListener, ErrorListener errorListener) {
        super(method, url, errorListener);
        this.mMethod = method;
        this.mUrl = url;
        this.mParams = params;
        this.mListener = reponseListener;
    }

@Override
public String getUrl() {
    if(mMethod == Request.Method.GET) {
        if(mParams != null) {
            StringBuilder stringBuilder = new StringBuilder(mUrl);
            Iterator<Map.Entry<String, String>> iterator = mParams.entrySet().iterator();
            int i = 1;
            while (iterator.hasNext()) {
                Map.Entry<String, String> entry = iterator.next();
                if (i == 1) {
                    stringBuilder.append("?" + entry.getKey() + "=" + entry.getValue());
                } else {
                    stringBuilder.append("&" + entry.getKey() + "=" + entry.getValue());
                }
                iterator.remove(); // avoids a ConcurrentModificationException
                i++;
            }
            mUrl = stringBuilder.toString();
        }
    }
    return mUrl;
}

    @Override
    protected Map<String, String> getParams()
            throws com.android.volley.AuthFailureError {
        return mParams;
    };

    @Override
    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
        try {
            String jsonString = new String(response.data,
                    HttpHeaderParser.parseCharset(response.headers));
            return Response.success(new JSONObject(jsonString),
                    HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (JSONException je) {
            return Response.error(new ParseError(je));
        }
    }

    @Override
    protected void deliverResponse(JSONObject response) {
        // TODO Auto-generated method stub
        mListener.onResponse(response);
    }
}
Mariande answered 16/10, 2015 at 1:50 Comment(4)
This solves adding parameters to the GET method, Thank You!Theotokos
In our case the iterator approach destroyed the original Map params object we passed to the function. Seems Volley internally calls GetUrl several times. We ended up with a classic foreach approach as posted in a separate answer. Hope this helps who lands here. :)Peccant
How to call this helper class for get request with 3 parametersDioptometer
@kgandroid, create a Map<String, String> with your keys and values. Example: Map<String, String> params = new HashMap<String, String>(); params.put("param1", "value1"); params.put("param2", "value2"); params.put("param3", "value3");Mariande
P
6

Dealing with GET parameters I iterated on Andrea Motto' solution. The problem was that Volley called GetUrl several times and his solution, using an Iterator, destroyed original Map object. The subsequent Volley internal calls had an empty params object.

I added also the encode of parameters.

This is an inline usage (no subclass).

public void GET(String url, Map<String, String> params, Response.Listener<String> response_listener, Response.ErrorListener error_listener, String API_KEY, String stringRequestTag) {
    final Map<String, String> mParams = params;
    final String mAPI_KEY = API_KEY;
    final String mUrl = url;

    StringRequest stringRequest = new StringRequest(
            Request.Method.GET,
            mUrl,
            response_listener,
            error_listener
    ) {
        @Override
        protected Map<String, String> getParams() {
            return mParams;
        }

        @Override
        public String getUrl() {
            StringBuilder stringBuilder = new StringBuilder(mUrl);
            int i = 1;
            for (Map.Entry<String,String> entry: mParams.entrySet()) {
                String key;
                String value;
                try {
                    key = URLEncoder.encode(entry.getKey(), "UTF-8");
                    value = URLEncoder.encode(entry.getValue(), "UTF-8");
                    if(i == 1) {
                        stringBuilder.append("?" + key + "=" + value);
                    } else {
                        stringBuilder.append("&" + key + "=" + value);
                    }
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                i++;

            }
            String url = stringBuilder.toString();

            return url;
        }

        @Override
        public Map<String, String> getHeaders() {
            Map<String, String> headers = new HashMap<>();
            if (!(mAPI_KEY.equals(""))) {
                headers.put("X-API-KEY", mAPI_KEY);
            }
            return headers;
        }
    };

    if (stringRequestTag != null) {
        stringRequest.setTag(stringRequestTag);
    }

    mRequestQueue.add(stringRequest);
}

This function uses headers to pass an APIKEY and sets a TAG to the request useful to cancel it before its completion.

Hope this helps.

Peccant answered 19/4, 2016 at 16:1 Comment(0)
E
3

This may help you...

private void loggedInToMainPage(final String emailName, final String passwordName) {

    String tag_string_req = "req_login";
    StringRequest stringRequest = new StringRequest(Request.Method.POST, "http://localhost/index", new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            Log.d(TAG, "Login Response: " + response.toString());
            try {
                JSONObject jsonObject = new JSONObject(response);
                Boolean error = jsonObject.getBoolean("error");
                if (!error) {

                    String uid = jsonObject.getString("uid");
                    JSONObject user = jsonObject.getJSONObject("user");
                    String email = user.getString("email");
                    String password = user.getString("password");


                    session.setLogin(true);
                    Intent intent = new Intent(getApplicationContext(), MainActivity.class);
                    startActivity(intent);
                    finish();
                    Toast.makeText(getApplicationContext(), "its ok", Toast.LENGTH_SHORT).show();
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }

        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError volleyError) {
            System.out.println("volley Error .................");
        }
    }) {
        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            Map<String, String> params = new HashMap<String, String>();
            params.put("tag", "login");
            params.put("email", emailName);
            params.put("password", passwordName);
            return params;
        }
    };


    MyApplication.getInstance().addToRequestQueue(stringRequest,tag_string_req);
}
Endocranium answered 12/4, 2016 at 12:48 Comment(0)
V
2

For Future Readers

I love to work with Volley. To save development time i tried to write small handy library Gloxey Netwok Manager to setup Volley with my project. It includes JSON parser and different other methods that helps to check network availability.

Use ConnectionManager.class in which different methods for Volley String and Volley JSON request are available. You can make requests of GET, PUT, POST, DELETE with or without header. You can read full documentation here.

Just put this line in your gradle file.

  dependencies { 

       compile 'io.gloxey.gnm:network-manager:1.0.1'
   }

Volley StringRequest

Method GET (without header)

    ConnectionManager.volleyStringRequest(context, isDialog, progressDialogView, requestURL, volleyResponseInterface);

How to use?

     Configuration                Description

     Context                      Context 
     isDialog                     If true dialog will appear, otherwise not.
     progressView                 For custom progress view supply your progress view id and make isDialog true. otherwise pass null. 
     requestURL                   Pass your API URL.  
     volleyResponseInterface      Callback for response.  

Example

    ConnectionManager.volleyStringRequest(this, false, null, "url", new VolleyResponse() {
    @Override
    public void onResponse(String _response) {

        /**
         * Handle Response
         */
    }

    @Override
     public void onErrorResponse(VolleyError error) {

        /**
         * handle Volley Error
         */
    }

    @Override
    public void isNetwork(boolean connected) {

        /**
         * True if internet is connected otherwise false
         */
    }
});

Volley StringRequest

Method POST/PUT/DELETE (without header)

    ConnectionManager.volleyStringRequest(context, isDialog, progressDialogView, requestURL, requestMethod, params, volleyResponseInterface);

Example

Use Method : Request.Method.POST
             Request.Method.PUT
             Request.Method.DELETE

Your params : 

HashMap<String, String> params = new HashMap<>();
params.put("param 1", "value");
params.put("param 2", "value");

ConnectionManager.volleyStringRequest(this, true, null, "url", Request.Method.POST, params, new VolleyResponse() {
    @Override
    public void onResponse(String _response) {

        /**
         * Handle Response
         */
    }

    @Override
    public void onErrorResponse(VolleyError error) {

        /**
         * handle Volley Error
         */
    }

    @Override
    public void isNetwork(boolean connected) {

        /**
         * True if internet is connected otherwise false
         */
    }
});

Bonus

Gloxey JSON Parser

Feel free to use gloxey json parser to parse your api response.

  YourModel yourModel = GloxeyJsonParser.getInstance().parse(stringResponse, YourModel.class);

Example

ConnectionManager.volleyStringRequest(this, false, null, "url", new VolleyResponse() {
    @Override
    public void onResponse(String _response) {

        /**
         * Handle Response
         */

         try {

          YourModel yourModel = GloxeyJsonParser.getInstance().parse(_response, YourModel.class);

            } catch (Exception e) {
                e.printStackTrace();
            }

    }

    @Override
     public void onErrorResponse(VolleyError error) {

        /**
         * handle Volley Error
         */
         if (error instanceof TimeoutError || error instanceof NoConnectionError) {

                showSnackBar(parentLayout, getString(R.string.internet_not_found), getString(R.string.retry), new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {

                     //handle retry button

                    }
                });

            } else if (error instanceof AuthFailureError) {
            } else if (error instanceof ServerError) {
            } else if (error instanceof NetworkError) {
            } else if (error instanceof ParseError) {
            }

    }

    @Override
    public void isNetwork(boolean connected) {

        /**
         * True if internet is connected otherwise false
         */
          if (!connected) {
                showSnackBar(parentLayout, getString(R.string.internet_not_found), getString(R.string.retry), new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        //Handle retry button
                    }
                });
    }
});


     public void showSnackBar(View view, String message) {
            Snackbar.make(view, message, Snackbar.LENGTH_LONG).show();
     }

     public void showSnackBar(View view, String message, String actionText, View.OnClickListener onClickListener) {
            Snackbar.make(view, message, Snackbar.LENGTH_LONG).setAction(actionText, onClickListener).show();
     }
Virus answered 18/7, 2017 at 20:0 Comment(2)
But does it support Method.GetMensa
Yes it does, please have a look for details. github.com/adnanbinmustafa/Gloxey-Network-ManagerVirus
F
0

To provide POST parameter send your parameter as JSONObject in to the JsonObjectRequest constructor. 3rd parameter accepts a JSONObject that is used in Request body.

JSONObject paramJson = new JSONObject();

paramJson.put("key1", "value1");
paramJson.put("key2", "value2");


JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST,url,paramJson,
    new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {

        }
    },
    new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {

        }
    });
requestQueue.add(jsonObjectRequest);
Fatimahfatimid answered 16/5, 2018 at 16:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.