Android multipart image upload with HttpConnectionParams deprecated in new api Android multipart image upload with HttpConnectionParams deprecated in new api json json

Android multipart image upload with HttpConnectionParams deprecated in new api


this is FileUploadMultipartRequest class:

/** * Multipart request for sending files over http * also can return generic type of response data * @param <T> the type of data for http responses */public class FileUploadMultipartRequest<T> extends BaseRequest<T>{    private static final MediaType JSON = MediaType.parse("application/json");    private File[] files;    private String jsonString;    private RequestBody requestBody;    public FileUploadMultipartRequest(String url, Map<String, String> headers, String jsonString, OnEmptyResponseListener listener, ErrorTypeListener errorListener, File... files)    {        super(Method.POST, url, headers, listener, new ErrorListenerImpl(errorListener));        this.jsonString = jsonString;        this.files = files;    }    public FileUploadMultipartRequest(String url, Map<String, String> headers, String jsonString, Type responseType, Response.Listener listener, ErrorTypeListener errorListener, File... files)    {        super(Method.POST, url, headers, responseType, listener, new ErrorListenerImpl(errorListener));        this.jsonString = jsonString;        this.files = files;    }    @Override    public String getBodyContentType()    {        return buildMultipartEntity().contentType().toString();    }    @Override    public byte[] getBody() throws AuthFailureError    {        Buffer buffer = new Buffer();        try        {            buildMultipartEntity().writeTo(buffer);        } catch (IOException e)        {            VolleyLog.e("IOException writing to ByteArrayOutputStream");        }        return buffer.readByteArray();    }    private RequestBody buildMultipartEntity()    {        if (requestBody == null)        {            MultipartBuilder multipartBuilder = new MultipartBuilder().type(MultipartBuilder.FORM);            multipartBuilder.addPart(                    Headers.of("Content-Disposition", "form-data; name=json-part"),                    RequestBody.create(JSON, jsonString));            for (File file : files)            {                String contentType = URLConnection.guessContentTypeFromName(file.getName());                multipartBuilder.addFormDataPart("files-part", file.getName(),                        RequestBody.create(MediaType.parse(contentType), file));            }            requestBody = multipartBuilder.build();        }        return requestBody;    }}

this is BaseRequest class:

/** * this a abstract request class for handling http http responses * note : all volley request should extend this class for http request * * @param <T> the type of data for http responses */public abstract class BaseRequest<T> extends Request<T>{    private final Map<String, String> headers;    /**     * the type response that {@link com.android.volley.Response.Listener} should return     */    private Type responseType;    /**     * generic listener for successful http request     */    private Response.Listener<T> listener;    /**     * constructor for request that returns data type {@link T}     *     * @param method        http verb e.g. POST, GET & etc     * @param url           request URL     * @param headers       http headers     * @param responseType  type of data that response should return     * @param listener      event for successful request     * @param errorListener event for failed request     */    public BaseRequest(int method, String url, Map<String, String> headers, Type responseType, Response.Listener listener, ErrorListenerImpl errorListener)    {        super(method, url, errorListener);        this.headers = headers;        this.responseType = responseType;        //noinspection unchecked        this.listener = listener;    }    /**     * constructor for requests with no returning data     *  @param method                  http verb e.g. POST, GET & etc     * @param url                     request URL     * @param headers                 http headers     * @param onEmptyResponseListener event for successful request (but no data return)     * @param errorListener           event for failed request     */    public BaseRequest(int method, String url, Map<String, String> headers, OnEmptyResponseListener onEmptyResponseListener, ErrorListenerImpl errorListener)    {        super(method, url, errorListener);        this.headers = headers;        //noinspection unchecked        listener = new OnEmptyResponseImpl(onEmptyResponseListener);    }    protected Response<T> parseNetworkResponse(NetworkResponse response)    {        // if response type is null so just pass null to success event        if (this.responseType == null && new String(response.data).isEmpty())        {            return Response.success(null, HttpHeaderParser.parseCacheHeaders(response));        }        // if response type is specified        try        {            Gson gson = new Gson();            String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));            // we use GSON to reflect response data to the generic type and pass to success event            T parseObject = gson.fromJson(json, responseType);            return Response.success(parseObject, HttpHeaderParser.parseCacheHeaders(response));        } catch (UnsupportedEncodingException e)        {            return Response.error(new ParseError(e));        } catch (JsonSyntaxException e)        {            return Response.error(new ParseError(e));        }    }    @Override    protected void deliverResponse(T response)    {        if (listener != null)        {            // call successful response event when listener not empty            listener.onResponse(response);        }    }    @Override    protected void onFinish()    {        super.onFinish();        listener = null;    }    /**     * this class forward response event to {@link com.khosravi.mehrdadz.garagesale.Network.RequestType.BaseRequest.OnEmptyResponseListener}     * when volley {@link com.android.volley.Response.Listener} is called     */    private static class OnEmptyResponseImpl implements Response.Listener    {        OnEmptyResponseListener onEmptyResponseListener;        /**         * @param onEmptyResponseListener interface for response with not data return         */        public OnEmptyResponseImpl(OnEmptyResponseListener onEmptyResponseListener)        {            this.onEmptyResponseListener = onEmptyResponseListener;        }        /**         * we call {@link com.khosravi.mehrdadz.garagesale.Network.RequestType.BaseRequest.OnEmptyResponseImpl#onEmptyResponseListener}         * when volley listener is class so no null object passed to the event         *         * @param response         */        @Override        public void onResponse(Object response)        {            onEmptyResponseListener.OnEmptyResponse();        }    }    /**     * interface for http response with no returning data     */    public interface OnEmptyResponseListener    {        void OnEmptyResponse();    }    public Map<String, String> getHeaders() throws AuthFailureError    {        return this.headers != null ? this.headers : super.getHeaders();    }}

and this is GsonRequest class:

@SuppressWarnings("JavaDoc")/** * Gson request that return generic type of response data * @param <T> the type of data for http responses */public class GsonRequest<T> extends BaseRequest<T>{    protected static final String PROTOCOL_CHARSET = "utf-8";    /**     * Content type for request.     */    private static final String PROTOCOL_CONTENT_TYPE =            String.format("application/json; charset=%s", PROTOCOL_CHARSET);    /**     * message body of http request     */    private final String requestBody;    /**     * Request return response object of Type {@link T}     * @param url     * @param headers     * @param type     * @param listener     * @param errorListener     */    public GsonRequest(String url, Map<String, String> headers, Type type, Listener<T> listener, ErrorTypeListener errorListener)    {        super(Method.GET, url, headers, type, listener, new ErrorListenerImpl(errorListener));        requestBody = null;    }    /**     * Request return response object of Type {@link T}     * @param url     * @param headers     * @param jsonObject json object to send with request     * @param type     * @param listener     * @param errorListener     */    public GsonRequest(String url, Map<String, String> headers, JSONObject jsonObject, Type type, Listener<T> listener, ErrorTypeListener errorListener)    {        super(Method.POST, url, headers, type, listener, new ErrorListenerImpl(errorListener));        this.requestBody = jsonObject == null ? null : jsonObject.toString();    }    /**     * Request return empty response     * @param url     * @param headers     * @param jsonObject json object to send with request     * @param listener     * @param errorListener     */    public GsonRequest(String url, Map<String, String> headers, JSONObject jsonObject, OnEmptyResponseListener listener, ErrorTypeListener errorListener)    {        super(Method.POST, url, headers, listener, new ErrorListenerImpl(errorListener));        this.requestBody = jsonObject == null ? null : jsonObject.toString();    }    /**     * Request return empty response     * @param url     * @param headers     * @param listener     * @param errorListener     */    public GsonRequest(String url, Map<String, String> headers, BaseRequest.OnEmptyResponseListener listener, ErrorTypeListener errorListener)    {        super(Method.GET, url, headers, listener, new ErrorListenerImpl(errorListener));        requestBody = null;    }    @Override    public String getBodyContentType()    {        return PROTOCOL_CONTENT_TYPE;    }    @Override    public byte[] getBody()    {        try        {            return requestBody == null ? null : requestBody.getBytes(PROTOCOL_CHARSET);        } catch (UnsupportedEncodingException uee)        {            VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s",                    requestBody, PROTOCOL_CHARSET);            return null;        }    }}

sample cod:

public class MyRequest{public MyRequest(Context context)    {        volleySingleton = VolleySingleton.getInstance(context);    }private static final String INSERT_NEW_PIC = "INSERT_NEW_PIC";public void UploadNewPic(File[] Images, BaseRequest.OnEmptyResponseListener listener, ErrorTypeListener errorListener)    {        FileUploadMultipartRequest fileUploadMultipartRequest = new FileUploadMultipartRequest("url", null, null, listener, errorListener,Images);        volleySingleton.addToRequestQueue(fileUploadMultipartRequest, INSERT_NEW_PIC);    }}

you can add more request to my request and call that anywhere.like this:

MyRequest myRequest;private HashMap<FrameLayout,File> Images;myRequest = new MyRequest(context);Images = new HashMap<>();myRequest.UploadNewPic(Images.values().toArray(new File[Images.values().size()]),  new BaseRequest.OnEmptyResponseListener()                    {                        @Override                        public void OnEmptyResponse()                        {                            Toast.makeText(getApplicationContext(), "added pics successfully", Toast.LENGTH_LONG).show();                            finish();                        }                    }, new ErrorTypeListener()                    {                        @Override                        public void onError(ErrorType errorType)                        {                        }                    });

server side cod (.net):

public class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider    {        public CustomMultipartFormDataStreamProvider(string path) : base(path) { }        //below only allows images and pdf files to be uploaded.        public override Stream GetStream(HttpContent parent, System.Net.Http.Headers.HttpContentHeaders headers)        {            // following line handles other form fields other than files.            if (String.IsNullOrEmpty(headers.ContentDisposition.FileName)) return base.GetStream(parent, headers);            // restrict what filetypes can be uploaded            List<string> extensions = new List<string> { "png", "gif",                "jpg", "jpeg", "tiff", "pdf", "tif", "bmp","doc","docx","ods","xls","odt","csv","txt","rtf" };            var filename = headers.ContentDisposition.FileName.Replace("\"", string.Empty); // correct for chrome.            //make sure it has an extension            if (filename.IndexOf('.') < 0)            {                return Stream.Null;            }            //get the extension            var extension = filename.Split('.').Last();            //Return stream if match otherwise return null stream.            return extensions.Contains(extension) ? base.GetStream(parent, headers) : Stream.Null;        }        public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)        {            var name = !string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName) ? headers.ContentDisposition.FileName : "NoName";            name = name.Replace("\"", string.Empty);            //name = (Guid.NewGuid()).ToString() +System.IO.Path.GetExtension(name); //this is here because Chrome submits files in quotation marks which get treated as part of the filename and get escaped            name = Path.GetRandomFileName().Replace(".", string.Empty) + Path.GetExtension(name); //this is here because Chrome submits files in quotation marks which get treated as part of the filename and get escaped            return name;        }    }

public class ImageRouteHandler :

IRouteHandler{    public IHttpHandler GetHttpHandler(RequestContext requestContext)    {        var filename = requestContext.RouteData.Values["filename"] as string;        var section = requestContext.RouteData.Values["section"] as string;        if (string.IsNullOrEmpty(filename) && string.IsNullOrEmpty(section))        {            // return a 404 HttpHandler here            requestContext.HttpContext.Response.StatusCode = 404;            requestContext.HttpContext.Response.End();            return null;        }        requestContext.HttpContext.Response.Clear();        requestContext.HttpContext.Response.Cache.SetMaxAge(TimeSpan.FromSeconds(500000));        requestContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.Public);        requestContext.HttpContext.Response.ContentType = GetContentType(filename);        // find physical path to image here.         var path = GetPath(section);        if (string.IsNullOrEmpty(path))        {            // return a 404 HttpHandler here            requestContext.HttpContext.Response.StatusCode = 404;            requestContext.HttpContext.Response.End();            return null;        }        var filepath = requestContext.HttpContext.Server.MapPath(path + filename);        requestContext.HttpContext.Response.WriteFile(filepath);        requestContext.HttpContext.Response.End();        return null;    }    private static string GetPath(string section)    {        switch (section)        {            case "user":                return "~/Resources/Users/";//where you want save pics in project        }        return "";    }    private static string GetContentType(string path)    {        switch (Path.GetExtension(path))        {            case ".bmp":                return "Image/bmp";            case ".gif":                return "Image/gif";            case ".jpg":                return "Image/jpeg";            case ".png":                return "Image/png";        }        return "";    }}

and change your RouteConfige like this:

public class RouteConfig    {        public static void RegisterRoutes(RouteCollection routes)        {            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");            // proccess all for protected resources with ImageRouteHandler            routes.Add("ImagesRoute", new Route("res/{section}/{filename}", new ImageRouteHandler()));            routes.MapRoute(                name: "Default",                url: "{controller}/{action}/{id}",                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }            );        }    }

sample code for server side:

public interface IUserManagement    {        void UploadNewPics( IEnumerable<string> imageUrls);    }    public class UserManagement : IUserManagement    {        public void UploadNewPics(IEnumerable<string> imageUrls)        {            using (var ctx = new Context())            {                foreach (var imageUrl in imageUrls)                {                    //save to data base                    .                    .                    .                }                try                {                    ctx.SaveChanges();                }                catch (Exception e)                {                    throw;                }            }        }    }        public class UserApiController : ApiController{    [HttpPost]    public async Task<IHttpActionResult> UploadNewPics()    {        if (!Request.Content.IsMimeMultipartContent())        {            throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);        }        var root = HttpContext.Current.Server.MapPath("~/Resources/Users/");        var provider = new CustomMultipartFormDataStreamProvider(root);        try        {            // Read the form data.            await Request.Content.ReadAsMultipartAsync(provider);            IUserManagement userManagement = new UserManagement();            var imageUrls = provider.FileData.Select(x=> Path.GetFileName(x.LocalFileName));            //userManagement.UploadUserImage(uploadImageJson, Path.GetFileName(imageFile.LocalFileName), (long)imageFile.Headers.ContentLength);            userManagement.UploadNewPics(imageUrls);        }        catch (Exception e)        {            return InternalServerError();        }        return Ok();    }}


IMO, you should use one of the following:

  1. OkHttp

  2. Retrofit

  3. Google's Volley

With Volley and Retrofit, yon can read my answers at Working POST Multipart Request with Volley and without HttpEntityand Retrofit - Multipart request: Required MultipartFile parameter 'file' is not present

Regaring OkHttp, please try My GitHub sample project with basic sample code as the following:

// Multipart request, upload file...        Drawable drawable = ContextCompat.getDrawable(mContext, R.drawable.ic_launcher);        if (drawable != null) {            Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();            ByteArrayOutputStream stream = new ByteArrayOutputStream();            bitmap.compress(Bitmap.CompressFormat.PNG, 0, stream);            final byte[] bitmapdata = stream.toByteArray();            OkHttpClient client = new OkHttpClient();            RequestBody requestBody = new MultipartBuilder()                    .type(MultipartBuilder.FORM)                    .addPart(                            Headers.of("Content-Disposition", "form-data; name=\"title\""),                            RequestBody.create(null, "Sample Text Content"))                    .addPart(                            Headers.of("Content-Disposition", "form-data; name=\"file\"; filename=\"ic_launcher.png\""),                            RequestBody.create(MEDIA_TYPE_PNG, bitmapdata))                    .build();            final Request request = new Request.Builder()                    .url("http://192.168.1.100:20583/fileupload")                    .post(requestBody)                    .build();            client.newCall(request).enqueue(new Callback() {                @Override                public void onFailure(final Request request, final IOException e) {                    Log.e(LOG_TAG, e.toString());                    mHandler.post(new Runnable() {                        @Override                        public void run() {                            Toast.makeText(mContext, e.toString(), Toast.LENGTH_SHORT).show();                            mTextView.setText(e.toString());                        }                    });                }                @Override                public void onResponse(Response response) throws IOException {                    final String message = response.toString();                    Log.i(LOG_TAG, message);                    mHandler.post(new Runnable() {                        @Override                        public void run() {                            Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();                            mTextView.setText(message);                        }                    });                }            });        }

Hope it helps!


Yeah as the Apache HTTPClient is deprecated now you can use HTTPURLConnection I used this code to send multiple files over gmail via SMTP, You modify the code and use it!

 public class sendMails extends AsyncTask<String, String, String> {    ProgressDialog progress;    public sendMails(Context context) {        progress = new ProgressDialog(context);    }    @Override    protected void onPreExecute() {        progress.setMessage("Contacting Server!" + "\nPlease make sure internet is working!");        progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);        progress.setIndeterminate(true);        progress.show();        progress.setCancelable(false);    }    @Override    protected String doInBackground(String... params) {        System.out.println("asd");        // Get system properties        Properties props = System.getProperties();        props.put("mail.smtp.host", "smtp.gmail.com");        props.put("mail.smtp.socketFactory.port", "465");        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");        props.put("mail.smtp.auth", "true");        props.put("mail.smtp.port", "465");        // Get session        Session session = Session.getDefaultInstance(props, new javax.mail.Authenticator() {            protected PasswordAuthentication getPasswordAuthentication() {                return new PasswordAuthentication("EMAIL ADDRESS", "password");// return new PasswordAuthentication("", "password");            }        });        try {            // Define message            MimeMessage message = new MimeMessage(session);            message.setFrom(new InternetAddress("EMAIL ADDRESS"));            // Set To: header field of the header.            message.setRecipients(Message.RecipientType.TO,                    InternetAddress.parse(email));            message.setSubject("Your Photos");            String text = "Content";            message.setText(text);            Multipart multipart = new MimeMultipart("mixed");            for (String str : listOfImages) {                System.out.println(str);                MimeBodyPart messageBodyPart = new MimeBodyPart();                DataSource source = new FileDataSource(str);                messageBodyPart.setDataHandler(new DataHandler(source));                messageBodyPart.setFileName(source.getName());                multipart.addBodyPart(messageBodyPart);            }            message.setContent(multipart);            // Send message            Transport.send(message);        } catch (AddressException e) {            e.printStackTrace();        } catch (MessagingException e) {            e.printStackTrace();        }        return "";    }    @Override    protected void onPostExecute(String s) {        setupScreenOnReciever();        progress.dismiss();    }}