Thursday, 7 August 2014

Creating custom volley request to send multipart data

Volley is an HTTP library that makes networking for Android apps easier and most importantly, faster. Volley is available through the open AOSP repository.


Volley offers the following benefits:
  • Automatic scheduling of network requests.
  • Multiple concurrent network connections.
  • Transparent disk and memory response caching with standard HTTP cache coherence.
  • Support for request prioritization.
  • Cancellation request API. You can cancel a single request, or you can set blocks or scopes of requests to cancel.
  • Ease of customization, for example, for retry and backoff.
  • Strong ordering that makes it easy to correctly populate your UI with data fetched asynchronously from the network.
  • Debugging and tracing tools.
To get an overview of volley I would suggest you to watch this video by Ficus Kirkpatrick at Google I/O 2013 .

Volley doesn't provide support for Multipart request . But we can use volley's framework and provide our own implementation of HttpStack .

The following code creates a custom volley request that can be used to send multipart data .

import java.io.ByteArrayOutputStream;  
 import java.io.File;  
 import java.io.IOException;  
 import java.io.UnsupportedEncodingException;  
 import java.util.HashMap;  
 import java.util.Map;  
 import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;  
 import org.apache.http.entity.mime.HttpMultipartMode;  
 import org.apache.http.entity.mime.MultipartEntity;  
 import org.apache.http.entity.mime.content.FileBody;  
 import org.apache.http.entity.mime.content.StringBody;  
 import android.util.Log;  
 import com.android.volley.AuthFailureError;  
 import com.android.volley.NetworkResponse;  
 import com.android.volley.Request;  
 import com.android.volley.Response;  
 import com.android.volley.VolleyLog;  
 import com.android.volley.Response.ErrorListener;  
 public class MultiPartReq extends Request < String > {  
      private Response.Listener < String > mListener = null;  
      private Response.ErrorListener mEListener;  
      //       
      private final File mFilePart;  
      private final String mStringPart;  
      private Map < String, String > parameters;  
      private Map < String, String > header;  
      MultipartEntity entity = new MultipartEntity();  
      @Override  
      public Map < String, String > getHeaders() throws AuthFailureError {  
           return header;  
      }  
      public MultiPartReq(String url, Response.ErrorListener eListener,  
      Response.Listener < String > rListener, File file, String stringPart,  
      Map < String, String > param, Map < String, String > head) {  
           super(Method.POST, url, eListener);  
           mListener = rListener;  
           mEListener = eListener;  
           mFilePart = file;  
           mStringPart = stringPart;  
           parameters = param;  
           header = head;  
           buildMultipartEntity();  
      }  
      @Override  
      public String getBodyContentType() {  
           return entity.getContentType().getValue();  
      }  
      @Override  
      public byte[] getBody() throws AuthFailureError {  
           ByteArrayOutputStream bos = new ByteArrayOutputStream();  
           try {  
                entity.writeTo(bos);  
                String entityContentAsString = new String(bos.toByteArray());  
                Log.e("volley", entityContentAsString);  
           } catch (IOException e) {  
                VolleyLog.e("IOException writing to ByteArrayOutputStream");  
           }  
           return bos.toByteArray();  
      }  
      @Override  
      protected void deliverResponse(String arg0) {  
           // TODO Auto-generated method stub  
      }  
      @Override  
      protected Response < String > parseNetworkResponse(NetworkResponse response) {  
           // TODO Auto-generated method stub  
           return null;  
      }  
      private void buildMultipartEntity() {  
           entity.addPart(mStringPart, new FileBody(mFilePart));  
           try {  
                for (String key: parameters.keySet())  
                entity.addPart(key, new StringBody(parameters.get(key)));  
           } catch (UnsupportedEncodingException e) {  
                VolleyLog.e("UnsupportedEncodingException");  
           }  
      }  

Now create a object of the above class and add it to the request queue .

 File f = new File("path");  
           HashMap<String, String> headers = new HashMap<String, String>();  
           headers.put("key", "value");  
           //headers.put("Authorization", "Token "+pref.getString("token", "123"));   
           //File f = new File(s);  
           HashMap<String, String> params = new HashMap<String, String>();  
           params.put("key","value");  
           mPR = new MultiPartReq("http://api.jhjh.com/api/v1/mmnbn/create/", new Response.ErrorListener() {  
                @Override  
                public void onErrorResponse(VolleyError arg0) {  
                     // TODO Auto-generated method stub  
                     Toast.makeText(getActivity(), "error "+arg0.toString(), Toast.LENGTH_LONG).show();  
                }       
           } , new Response.Listener<String>() {  
                @Override  
                public void onResponse(String arg0) {  
                     // TODO Auto-generated method stub  
                     Log.d("Success", arg0.toString());  
                }  
           }, f, "filekey", params , headers);  
           AppController.getInstance().addToRequestQueue(mPR,  
                     "request tag ");  

In your project create a class named  AppController.java and add the following code to it .

 import android.app.Application;  
 import android.text.TextUtils;  
 import com.android.volley.Request;  
 import com.android.volley.RequestQueue;  
 import com.android.volley.toolbox.ImageLoader;  
 import com.android.volley.toolbox.Volley;  
 public class AppController extends Application {  
      private ImageLoader mImageLoader;  
      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());  
           }  
           return mRequestQueue;  
      }  
      public <T> void addToRequestQueue(Request<T> req, String tag) {  
           // set the default tag if tag is empty  
           req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);  
           getRequestQueue().add(req);  
      }  
      public <T> void addToRequestQueue(Request<T> req) {  
           req.setTag(TAG);  
           getRequestQueue().add(req);  
      }  
      public void cancelPendingRequests(Object tag) {  
           if (mRequestQueue != null) {  
                mRequestQueue.cancelAll(tag);  
           }  
      }  
      public ImageLoader getImageLoader() {  
           getRequestQueue();  
           if (mImageLoader == null) {  
                mImageLoader = new ImageLoader(this.mRequestQueue,  
                          new ThoughtImageCache());  
           }  
           return this.mImageLoader;  
      }  
 }  






3 comments:

  1. Code doesn't work seems it can't find ContentType in httpmime even though it is there. Is there something in the gradle build I need to do? I have this...compile 'org.apache.httpcomponents:httpmime:4.3.5'

    ReplyDelete