Send POST request with JSON data using Volley

前端 未结 8 691
梦谈多话
梦谈多话 2020-11-22 12:07

I would like to send a new JsonObjectRequest request:

  • I want to receive JSON data (response from server): OK
  • I want to send JSON form

8条回答
  •  一生所求
    2020-11-22 12:41

    I know that this thread is quite old, but I had this problem and I came up with a cool solution which can be very useful to many because it corrects/extended the Volley library on many aspects.

    I spotted some not supported-out-of-box Volley features:

    • This JSONObjectRequest is not perfect: you have to expect a JSON at the end (see the Response.Listener).
    • What about Empty Responses (just with a 200 status)?
    • What do I do if I want directly my POJO from the ResponseListener?

    I more or less compiled a lot of solutions in a big generic class in order to have a solution for all the problem I quoted.

      /**
      * Created by laurentmeyer on 25/07/15.
      */
     public class GenericRequest extends JsonRequest {
    
         private final Gson gson = new Gson();
         private final Class clazz;
         private final Map headers;
         // Used for request which do not return anything from the server
         private boolean muteRequest = false;
    
         /**
          * Basically, this is the constructor which is called by the others.
          * It allows you to send an object of type A to the server and expect a JSON representing a object of type B.
          * The problem with the #JsonObjectRequest is that you expect a JSON at the end.
          * We can do better than that, we can directly receive our POJO.
          * That's what this class does.
          *
          * @param method:        HTTP Method
          * @param classtype:     Classtype to parse the JSON coming from the server
          * @param url:           url to be called
          * @param requestBody:   The body being sent
          * @param listener:      Listener of the request
          * @param errorListener: Error handler of the request
          * @param headers:       Added headers
          */
         private GenericRequest(int method, Class classtype, String url, String requestBody,
                               Response.Listener listener, Response.ErrorListener errorListener, Map headers) {
             super(method, url, requestBody, listener,
                     errorListener);
             clazz = classtype;
             this.headers = headers;
             configureRequest();
         }
    
         /**
          * Method to be called if you want to send some objects to your server via body in JSON of the request (with headers and not muted)
          *
          * @param method:        HTTP Method
          * @param url:           URL to be called
          * @param classtype:     Classtype to parse the JSON returned from the server
          * @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server
          * @param listener:      Listener of the request
          * @param errorListener: Error handler of the request
          * @param headers:       Added headers
          */
         public GenericRequest(int method, String url, Class classtype, Object toBeSent,
                               Response.Listener listener, Response.ErrorListener errorListener, Map headers) {
             this(method, classtype, url, new Gson().toJson(toBeSent), listener,
                     errorListener, headers);
         }
    
         /**
          * Method to be called if you want to send some objects to your server via body in JSON of the request (without header and not muted)
          *
          * @param method:        HTTP Method
          * @param url:           URL to be called
          * @param classtype:     Classtype to parse the JSON returned from the server
          * @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server
          * @param listener:      Listener of the request
          * @param errorListener: Error handler of the request
          */
         public GenericRequest(int method, String url, Class classtype, Object toBeSent,
                               Response.Listener listener, Response.ErrorListener errorListener) {
             this(method, classtype, url, new Gson().toJson(toBeSent), listener,
                     errorListener, new HashMap());
         }
    
         /**
          * Method to be called if you want to send something to the server but not with a JSON, just with a defined String (without header and not muted)
          *
          * @param method:        HTTP Method
          * @param url:           URL to be called
          * @param classtype:     Classtype to parse the JSON returned from the server
          * @param requestBody:   String to be sent to the server
          * @param listener:      Listener of the request
          * @param errorListener: Error handler of the request
          */
         public GenericRequest(int method, String url, Class classtype, String requestBody,
                               Response.Listener listener, Response.ErrorListener errorListener) {
             this(method, classtype, url, requestBody, listener,
                     errorListener, new HashMap());
         }
    
         /**
          * Method to be called if you want to GET something from the server and receive the POJO directly after the call (no JSON). (Without header)
          *
          * @param url:           URL to be called
          * @param classtype:     Classtype to parse the JSON returned from the server
          * @param listener:      Listener of the request
          * @param errorListener: Error handler of the request
          */
         public GenericRequest(String url, Class classtype, Response.Listener listener, Response.ErrorListener errorListener) {
             this(Request.Method.GET, url, classtype, "", listener, errorListener);
         }
    
         /**
          * Method to be called if you want to GET something from the server and receive the POJO directly after the call (no JSON). (With headers)
          *
          * @param url:           URL to be called
          * @param classtype:     Classtype to parse the JSON returned from the server
          * @param listener:      Listener of the request
          * @param errorListener: Error handler of the request
          * @param headers:       Added headers
          */
         public GenericRequest(String url, Class classtype, Response.Listener listener, Response.ErrorListener errorListener, Map headers) {
             this(Request.Method.GET, classtype, url, "", listener, errorListener, headers);
         }
    
         /**
          * Method to be called if you want to send some objects to your server via body in JSON of the request (with headers and muted)
          *
          * @param method:        HTTP Method
          * @param url:           URL to be called
          * @param classtype:     Classtype to parse the JSON returned from the server
          * @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server
          * @param listener:      Listener of the request
          * @param errorListener: Error handler of the request
          * @param headers:       Added headers
          * @param mute:          Muted (put it to true, to make sense)
          */
         public GenericRequest(int method, String url, Class classtype, Object toBeSent,
                               Response.Listener listener, Response.ErrorListener errorListener, Map headers, boolean mute) {
             this(method, classtype, url, new Gson().toJson(toBeSent), listener,
                     errorListener, headers);
             this.muteRequest = mute;
         }
    
         /**
          * Method to be called if you want to send some objects to your server via body in JSON of the request (without header and muted)
          *
          * @param method:        HTTP Method
          * @param url:           URL to be called
          * @param classtype:     Classtype to parse the JSON returned from the server
          * @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server
          * @param listener:      Listener of the request
          * @param errorListener: Error handler of the request
          * @param mute:          Muted (put it to true, to make sense)
          */
         public GenericRequest(int method, String url, Class classtype, Object toBeSent,
                               Response.Listener listener, Response.ErrorListener errorListener, boolean mute) {
             this(method, classtype, url, new Gson().toJson(toBeSent), listener,
                     errorListener, new HashMap());
             this.muteRequest = mute;
    
         }
    
         /**
          * Method to be called if you want to send something to the server but not with a JSON, just with a defined String (without header and not muted)
          *
          * @param method:        HTTP Method
          * @param url:           URL to be called
          * @param classtype:     Classtype to parse the JSON returned from the server
          * @param requestBody:   String to be sent to the server
          * @param listener:      Listener of the request
          * @param errorListener: Error handler of the request
          * @param mute:          Muted (put it to true, to make sense)
          */
         public GenericRequest(int method, String url, Class classtype, String requestBody,
                               Response.Listener listener, Response.ErrorListener errorListener, boolean mute) {
             this(method, classtype, url, requestBody, listener,
                     errorListener, new HashMap());
             this.muteRequest = mute;
    
         }
    
    
         @Override
         protected Response parseNetworkResponse(NetworkResponse response) {
             // The magic of the mute request happens here
             if (muteRequest) {
                 if (response.statusCode >= 200 && response.statusCode <= 299) {
                     // If the status is correct, we return a success but with a null object, because the server didn't return anything
                     return Response.success(null, HttpHeaderParser.parseCacheHeaders(response));
                 }
             } else {
                 try {
                     // If it's not muted; we just need to create our POJO from the returned JSON and handle correctly the errors
                     String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
                     T parsedObject = gson.fromJson(json, clazz);
                     return Response.success(parsedObject, HttpHeaderParser.parseCacheHeaders(response));
                 } catch (UnsupportedEncodingException e) {
                     return Response.error(new ParseError(e));
                 } catch (JsonSyntaxException e) {
                     return Response.error(new ParseError(e));
                 }
             }
             return null;
         }
    
         @Override
         public Map getHeaders() throws AuthFailureError {
             return headers != null ? headers : super.getHeaders();
         }
    
         private void configureRequest() {
             // Set retry policy
             // Add headers, for auth for example
             // ...
         }
     }
    

    It could seem a bit overkill but it's pretty cool to have all these constructors because you have all the cases:

    (The main constructor wasn't meant to be used directly although it's, of course, possible).

    1. Request with response parsed to POJO / Headers manually set / POJO to Send
    2. Request with response parsed to POJO / POJO to Send
    3. Request with response parsed to POJO / String to Send
    4. Request with response parsed to POJO (GET)
    5. Request with response parsed to POJO (GET) / Headers manually set
    6. Request with no response (200 - Empty Body) / Headers manually set / POJO to Send
    7. Request with no response (200 - Empty Body) / POJO to Send
    8. Request with no response (200 - Empty Body) / String to Send

    Of course, in order that it works, you have to have Google's GSON Lib; just add:

    compile 'com.google.code.gson:gson:x.y.z'
    

    to your dependencies (current version is 2.3.1).

提交回复
热议问题