Send POST request with JSON data using Volley

前端 未结 8 618
梦谈多话
梦谈多话 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<JSONObject>).
    • 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<T> extends JsonRequest<T> {
    
         private final Gson gson = new Gson();
         private final Class<T> clazz;
         private final Map<String, String> 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<T> classtype, String url, String requestBody,
                               Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> 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<T> classtype, Object toBeSent,
                               Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> 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<T> classtype, Object toBeSent,
                               Response.Listener<T> listener, Response.ErrorListener errorListener) {
             this(method, classtype, url, new Gson().toJson(toBeSent), listener,
                     errorListener, new HashMap<String, String>());
         }
    
         /**
          * 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<T> classtype, String requestBody,
                               Response.Listener<T> listener, Response.ErrorListener errorListener) {
             this(method, classtype, url, requestBody, listener,
                     errorListener, new HashMap<String, String>());
         }
    
         /**
          * 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<T> classtype, Response.Listener<T> 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<T> classtype, Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> 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<T> classtype, Object toBeSent,
                               Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> 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<T> classtype, Object toBeSent,
                               Response.Listener<T> listener, Response.ErrorListener errorListener, boolean mute) {
             this(method, classtype, url, new Gson().toJson(toBeSent), listener,
                     errorListener, new HashMap<String, String>());
             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<T> classtype, String requestBody,
                               Response.Listener<T> listener, Response.ErrorListener errorListener, boolean mute) {
             this(method, classtype, url, requestBody, listener,
                     errorListener, new HashMap<String, String>());
             this.muteRequest = mute;
    
         }
    
    
         @Override
         protected Response<T> 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<String, String> 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).

    0 讨论(0)
  • 2020-11-22 12:41
        final String url = "some/url";
    

    instead of:

        final JSONObject jsonBody = "{\"type\":\"example\"}";
    

    you can use:

      JSONObject jsonBody = new JSONObject();
        try {
            jsonBody.put("type", "my type");
        } catch (JSONException e) {
            e.printStackTrace();
        }
    new JsonObjectRequest(url, jsonBody, new Response.Listener<JSONObject>() { ... });
    
    0 讨论(0)
  • 2020-11-22 12:42

    You can also send data by overriding getBody() method of JsonObjectRequest class. As shown below.

        @Override
        public byte[] getBody()
        {
    
            JSONObject jsonObject = new JSONObject();
            String body = null;
            try
            {
                jsonObject.put("username", "user123");
                jsonObject.put("password", "Pass123");
    
                body = jsonObject.toString();
            } catch (JSONException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            try
            {
                return body.toString().getBytes("utf-8");
            } catch (UnsupportedEncodingException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }
    
    0 讨论(0)
  • 2020-11-22 12:51

    JsonObjectRequest actually accepts JSONObject as body.

    From this blog article,

    final String url = "some/url";
    final JSONObject jsonBody = new JSONObject("{\"type\":\"example\"}");
    
    new JsonObjectRequest(url, jsonBody, new Response.Listener<JSONObject>() { ... });
    

    Here is the source code and JavaDoc (@param jsonRequest):

    /**
     * Creates a new request.
     * @param method the HTTP method to use
     * @param url URL to fetch the JSON from
     * @param jsonRequest A {@link JSONObject} to post with the request. Null is allowed and
     *   indicates no parameters will be posted along with request.
     * @param listener Listener to receive the JSON response
     * @param errorListener Error listener, or null to ignore errors.
     */
    public JsonObjectRequest(int method, String url, JSONObject jsonRequest,
            Listener<JSONObject> listener, ErrorListener errorListener) {
        super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,
                    errorListener);
    }
    
    0 讨论(0)
  • 2020-11-22 12:53
    • Create an object of RequestQueue class.

      RequestQueue queue = Volley.newRequestQueue(this);
      
    • Create a StringRequest with response and error listener.

       StringRequest sr = new StringRequest(Request.Method.POST,"http://api.someservice.com/post/comment", new Response.Listener<String>() {
          @Override
          public void onResponse(String response) {
              mPostCommentResponse.requestCompleted();
          }
      }, new Response.ErrorListener() {
          @Override
          public void onErrorResponse(VolleyError error) {
              mPostCommentResponse.requestEndedWithError(error);
          }
      }){
          @Override
          protected Map<String,String> getParams(){
              Map<String,String> params = new HashMap<String, String>();
              params.put("user",userAccount.getUsername());
              params.put("pass",userAccount.getPassword());
              params.put("comment", Uri.encode(comment));
              params.put("comment_post_ID",String.valueOf(postId));
              params.put("blogId",String.valueOf(blogId));
      
              return params;
          }
      
          @Override
          public Map<String, String> getHeaders() throws AuthFailureError {
              Map<String,String> params = new HashMap<String, String>();
              params.put("Content-Type","application/x-www-form-urlencoded");
              return params;
          }
      };
      
    • Add your request into the RequestQueue.

      queue.add(jsObjRequest);
      
    • Create PostCommentResponseListener interface just so you can see it. It’s a simple delegate for the async request.

      public interface PostCommentResponseListener {
      public void requestStarted();
      public void requestCompleted();
      public void requestEndedWithError(VolleyError error);
      }
      
    • Include INTERNET permission inside AndroidManifest.xml file.

      <uses-permission android:name="android.permission.INTERNET"/>
      
    0 讨论(0)
  • 2020-11-22 12:53
    protected Map<String, String> getParams() {
       Map<String, String> params = new HashMap<String, String>();
    
       JSONObject JObj = new JSONObject();
    
       try {
               JObj.put("Id","1");
               JObj.put("Name", "abc");
    
       } catch (Exception e) {
           e.printStackTrace();
       }
    
       params.put("params", JObj.toString());
       // Map.Entry<String,String>
       Log.d("Parameter", params.toString());
       return params;
    }
    
    0 讨论(0)
提交回复
热议问题