How upload image with volley android to MVC api post method.I have tried this :
StringRequest stringRequest = new StringRequest(Request.Method.POST, UPLOAD_URL,
new Response.Listener<String>() {
#Override
public void onResponse(String responec) {
loading.dismiss();
Log.e("tag","data :"+responec);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
loading.dismiss();
Log.e("tag","data :"+volleyError.toString());
}
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
String image = getStringImage(bitmap);
Map<String,String> params = new Hashtable<String, String>();
params.put(KEY_IMAGE, image);
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(stringRequest);
how can I handle this.
This was the thing in one of my project that I had faced with several years ago and I just remind it and maybe can help you:
I writ this class to upload an image with a MVC API:
import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.HttpHeaderParser;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
/**
* Custom request to make multipart header and upload file.
* <p>
* Created by vahid on 27/04/2017 12.05.
*/
public class VolleyMultipartRequest extends Request<NetworkResponse> {
private final String twoHyphens = "--";
private final String lineEnd = "\r\n";
private final String boundary = "apiclient-" + System.currentTimeMillis();
private Response.Listener<NetworkResponse> mListener;
private Response.ErrorListener mErrorListener;
private Map<String, String> mHeaders;
/**
* Default constructor with predefined header and post method.
*
* #param url request destination
* #param headers predefined custom header
* #param listener on success achieved 200 code from request
* #param errorListener on error http or library timeout
*/
public VolleyMultipartRequest(String url, Map<String, String> headers, Response.Listener<NetworkResponse> listener, Response.ErrorListener errorListener) {
super(Method.POST, url, errorListener); this.mListener = listener;
this.mErrorListener = errorListener; this.mHeaders = headers;
}
/**
* Constructor with option method and default header configuration.
*
* #param method method for now accept POST and GET only
* #param url request destination
* #param listener on success event handler
* #param errorListener on error event handler
*/
public VolleyMultipartRequest(int method, String url, Response.Listener<NetworkResponse> listener, Response.ErrorListener errorListener) {
super(method, url, errorListener); this.mListener = listener;
this.mErrorListener = errorListener;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
return (mHeaders != null) ? mHeaders : super.getHeaders();
}
#Override
public String getBodyContentType() {
return "multipart/form-data;boundary=" + boundary;
}
#Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
try {
// populate text payload
Map<String, String> params = getParams();
if (params != null && params.size() > 0) {
textParse(dos, params, getParamsEncoding());
}
// populate data byte payload
Map<String, DataPart> data = getByteData();
if (data != null && data.size() > 0) {
dataParse(dos, data);
}
// close multipart form data after text and file data
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} return null;
}
/**
* Custom method handle data payload.
*
* #return Map data part label with data byte
* #throws AuthFailureError
*/
protected Map<String, DataPart> getByteData() throws AuthFailureError {
return null;
}
#Override
protected Response<NetworkResponse> parseNetworkResponse(NetworkResponse response) {
try {
return Response.success(response, HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
return Response.error(new ParseError(e));
}
}
#Override
protected void deliverResponse(NetworkResponse response) {
mListener.onResponse(response);
}
#Override
public void deliverError(VolleyError error) {
mErrorListener.onErrorResponse(error);
}
/**
* Parse string map into data output stream by key and value.
*
* #param dataOutputStream data output stream handle string parsing
* #param params string inputs collection
* #param encoding encode the inputs, default UTF-8
* #throws IOException
*/
private void textParse(DataOutputStream dataOutputStream, Map<String, String> params, String encoding) throws IOException {
try {
for (Map.Entry<String, String> entry : params.entrySet()) {
buildTextPart(dataOutputStream, entry.getKey(), entry.getValue());
}
} catch (UnsupportedEncodingException uee) {
throw new RuntimeException("Encoding not supported: " + encoding, uee);
}
}
/**
* Parse data into data output stream.
*
* #param dataOutputStream data output stream handle file attachment
* #param data loop through data
* #throws IOException
*/
private void dataParse(DataOutputStream dataOutputStream, Map<String, DataPart> data) throws IOException {
for (Map.Entry<String, DataPart> entry : data.entrySet()) {
buildDataPart(dataOutputStream, entry.getValue(), entry.getKey());
}
}
/**
* Write string data into header and data output stream.
*
* #param dataOutputStream data output stream handle string parsing
* #param parameterName name of input
* #param parameterValue value of input
* #throws IOException
*/
private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
//dataOutputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd);
dataOutputStream.writeBytes(lineEnd);
dataOutputStream.writeBytes(parameterValue + lineEnd);
}
/**
* Write data file into header and data output stream.
*
* #param dataOutputStream data output stream handle data parsing
* #param dataFile data byte as DataPart from collection
* #param inputName name of data input
* #throws IOException
*/
private void buildDataPart(DataOutputStream dataOutputStream, DataPart dataFile, String inputName) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + inputName + "\"; filename=\"" + dataFile.getFileName() + "\"" + lineEnd);
if (dataFile.getType() != null && !dataFile.getType().trim().isEmpty()) {
dataOutputStream.writeBytes("Content-Type: " + dataFile.getType() + lineEnd);
} dataOutputStream.writeBytes(lineEnd);
ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dataFile.getContent());
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1024 * 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dataOutputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
dataOutputStream.writeBytes(lineEnd);
}
/**
* Simple data container use for passing byte file
*/
public class DataPart {
private String fileName;
private byte[] content;
private String type;
/**
* Default data part
*/
public DataPart() {
}
/**
* Constructor with data.
*
* #param name label of data
* #param data byte data
*/
public DataPart(String name, byte[] data) {
fileName = name; content = data;
}
/**
* Constructor with mime data type.
*
* #param name label of data
* #param data byte data
* #param mimeType mime data like "image/jpeg"
*/
public DataPart(String name, byte[] data, String mimeType) {
fileName = name; content = data; type = mimeType;
}
/**
* Getter file name.
*
* #return file name
*/
public String getFileName() {
return fileName;
}
/**
* Setter file name.
*
* #param fileName string file name
*/
public void setFileName(String fileName) {
this.fileName = fileName;
}
/**
* Getter content.
*
* #return byte file data
*/
public byte[] getContent() {
return content;
}
/**
* Setter content.
*
* #param content byte file data
*/
public void setContent(byte[] content) {
this.content = content;
}
/**
* Getter mime type.
*
* #return mime type
*/
public String getType() {
return type;
}
/**
* Setter mime type.
*
* #param type mime type
*/
public void setType(String type) {
this.type = type;
}
}
}
and with this method you can use and upload anything :
private void uploadFile(final Drawable drawable, final String filePath, final String fileName, final String fileType, String url, final String mmtype) {
VolleyMultipartRequest multipartRequest = new VolleyMultipartRequest(Request.Method.POST, url, new Response.Listener<NetworkResponse>() {
#Override
public void onResponse(NetworkResponse response) {
String resultResponse = new String(response.data);
try {
JSONObject jsonObject = new JSONObject(resultResponse);
String type_of_file = jsonObject.getString("type");
if (type_of_file.matches("Voice")) {
} else if (type_of_file.matches("Video")) {
} else if (type_of_file.matches("Image")) {
url_uploaded_image.add(url_uploaded_image.size(), resultResponse);
}
} catch (JSONException e) {
e.printStackTrace();
}
// Log.e("tag", "response :" + resultResponse);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
Log.e("tag", "error :" + error.toString());
}
}) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
return params;
}
#Override
protected Map<String, DataPart> getByteData() {
Map<String, DataPart> params = new HashMap<>();
Log.e("tag", "data :" + params.toString());
params.put("", new DataPart(fileName + fileType, AppHelper.getFileDataFromFile(filePath)));
return params;
}
};
RequestQueue mRequestQueue = Volley.newRequestQueue(G.context);
mRequestQueue.add(multipartRequest);
}
For me i always encode the bitmap to a base64
using
public static String encodeToBase64(Bitmap image, Bitmap.CompressFormat compressFormat, int quality)
{
ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
image.compress(compressFormat, quality, byteArrayOS);
return Base64.encodeToString(byteArrayOS.toByteArray(), Base64.DEFAULT);
}
then send the base64 to your API ,,
in reverse mode decode the base64 and show the image using
public static Bitmap decodeBase64(String input)
{
byte[] decodedBytes = Base64.decode(input, 0);
return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
}
ImageViewObject.setImageBitmap();
Related
These my PHP Script Very well work check using postman upload photo successfully
But Problem is not Working on site code check my code its working efficient
postman outman working find in thse case android why not proper send data on serger if you guise are help they my work verywell done please please help it
require_once "connection.php";
$upload_path = 'upload/';
$server_ip = gethostbyname(gethostname());
$upload_url = 'http://'.$server_ip.'/shopping/'.$upload_path;
$responce = array();
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
if(isset($_POST['name']) and isset($_FILES['image']['name']))
{
global $connect;
$name = $_POST['name'];
$fileinfo = pathinfo($_FILES['image']['name']);
$extension = $fileinfo['extension'];
$file_url = $upload_url . getFileName() . '.'. $extension;
$file_path = $upload_path . getFileName() . '.'. $extension;
try{
move_uploaded_file($_FILES['image']['tmp_name'],$file_path);
$query = "INSERT INTO image(url,name) VALUES('$file_url','$name');";
mysqli_query($connect,$query);
{
$responce['error'] = false;
$responce['url'] = $file_url;
$responce['name'] = $name;
}
}
catch(Exception $e)
{
$responce['error'] = false;
$responce['message']=$e->getMessage();
}
//mysqli_close($connect);
}
else
{
$responce['error'] = true;
$responce['message'] = 'please choose file';
}
echo json_encode($responce);
}
function getFileName()
{
global $connect;
$sql = "SELECT MAX(id) as id FROM image";
$result = mysqli_fetch_array(mysqli_query($connect,$sql));
if($result['id'] == null)
{
return 1;
}
else
{
return ++$result['id'];
}
mysqli_close($connect);
}
?>
Php Code
These is My Android code please help me to solve these problem
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
ImageView imageAdd;
EditText name;
Button select,upload;
private Uri FilePath;
private Bitmap bitmap;
private String UPLOAD_URL = "http://192.168.0.103/shopping/file_upload.php";
private static final int STORAGE_PERMISSION_CODE = 2210;
private static final int PICK_IMAGE_REQUEST = 2310;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageAdd = findViewById(R.id.imageAdd);
name = findViewById(R.id.name);
select = findViewById(R.id.select);
upload = findViewById(R.id.upload);
select.setOnClickListener(this);
upload.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (v == upload){
uploadImage();
}
if (v == select){
ShowFileChooser();
}
}
//Open Dialog For Choose Images
private void ShowFileChooser(){
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"Select Picture"),PICK_IMAGE_REQUEST);
}
//Showing Result in ImageView
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null){
FilePath = data.getData();
try {
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),FilePath);
imageAdd.setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
}
}
} //over these method
private void uploadImage() {
final String NAME = name.getText().toString().trim();
StringRequest stringRequest = new StringRequest(Request.Method.POST, UPLOAD_URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response);
Toast.makeText(MainActivity.this, jsonObject.getString(response), Toast.LENGTH_LONG).show();
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MainActivity.this,error.getMessage(),Toast.LENGTH_LONG).show();
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> params = new HashMap<>();
params.put("url",convertBitmapToString(bitmap));
params.put("name",NAME);
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(stringRequest);
}
public String convertBitmapToString(Bitmap bmp) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, 100, stream); //compress to which format you want.
byte[] byte_arr = stream.toByteArray();
String imageStr = Base64.encodeToString(byte_arr, 1);
return imageStr;
}
you are using Base64 formate to upload which is not efficient way Case encoded Base64 string's length increase more than original one . You can upload image both Base64 way and Multi part way .I prefer multi-part process . I think below snap-net code gonna help you.
Create
VolleyMultipartRequest.class
public class VolleyMultipartRequest extends Request<NetworkResponse> {
private final String twoHyphens = "--";
private final String lineEnd = "\r\n";
private final String boundary = "apiclient-" + System.currentTimeMillis();
private Response.Listener<NetworkResponse> mListener;
private Response.ErrorListener mErrorListener;
private Map<String, String> mHeaders;
/**
* Default constructor with predefined header and post method.
*
* #param url request destination
* #param headers predefined custom header
* #param listener on success achieved 200 code from request
* #param errorListener on error http or library timeout
*/
public VolleyMultipartRequest(String url, Map<String, String> headers,
Response.Listener<NetworkResponse> listener,
Response.ErrorListener errorListener) {
super(Method.POST, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
this.mHeaders = headers;
}
/**
* Constructor with option method and default header configuration.
*
* #param method method for now accept POST and GET only
* #param url request destination
* #param listener on success event handler
* #param errorListener on error event handler
*/
public VolleyMultipartRequest(int method, String url,
Response.Listener<NetworkResponse> listener,
Response.ErrorListener errorListener) {
super(method, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
return (mHeaders != null) ? mHeaders : super.getHeaders();
}
#Override
public String getBodyContentType() {
return "multipart/form-data;boundary=" + boundary;
}
#Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
try {
// populate text payload
Map<String, String> params = getParams();
if (params != null && params.size() > 0) {
textParse(dos, params, getParamsEncoding());
}
// populate data byte payload
Map<String, DataPart> data = getByteData();
if (data != null && data.size() > 0) {
dataParse(dos, data);
}
// close multipart form data after text and file data
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* Custom method handle data payload.
*
* #return Map data part label with data byte
* #throws AuthFailureError
*/
protected Map<String, DataPart> getByteData() throws AuthFailureError {
return null;
}
#Override
protected Response<NetworkResponse> parseNetworkResponse(NetworkResponse response) {
try {
return Response.success(
response,
HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
return Response.error(new ParseError(e));
}
}
#Override
protected void deliverResponse(NetworkResponse response) {
mListener.onResponse(response);
}
#Override
public void deliverError(VolleyError error) {
mErrorListener.onErrorResponse(error);
}
/**
* Parse string map into data output stream by key and value.
*
* #param dataOutputStream data output stream handle string parsing
* #param params string inputs collection
* #param encoding encode the inputs, default UTF-8
* #throws IOException
*/
private void textParse(DataOutputStream dataOutputStream, Map<String, String> params, String encoding) throws IOException {
try {
for (Map.Entry<String, String> entry : params.entrySet()) {
buildTextPart(dataOutputStream, entry.getKey(), entry.getValue());
}
} catch (UnsupportedEncodingException uee) {
throw new RuntimeException("Encoding not supported: " + encoding, uee);
}
}
/**
* Parse data into data output stream.
*
* #param dataOutputStream data output stream handle file attachment
* #param data loop through data
* #throws IOException
*/
private void dataParse(DataOutputStream dataOutputStream, Map<String, DataPart> data) throws IOException {
for (Map.Entry<String, DataPart> entry : data.entrySet()) {
buildDataPart(dataOutputStream, entry.getValue(), entry.getKey());
}
}
/**
* Write string data into header and data output stream.
*
* #param dataOutputStream data output stream handle string parsing
* #param parameterName name of input
* #param parameterValue value of input
* #throws IOException
*/
private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
//dataOutputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd);
dataOutputStream.writeBytes(lineEnd);
dataOutputStream.writeBytes(parameterValue + lineEnd);
}
/**
* Write data file into header and data output stream.
*
* #param dataOutputStream data output stream handle data parsing
* #param dataFile data byte as DataPart from collection
* #param inputName name of data input
* #throws IOException
*/
private void buildDataPart(DataOutputStream dataOutputStream, DataPart dataFile, String inputName) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" +
inputName + "\"; filename=\"" + dataFile.getFileName() + "\"" + lineEnd);
if (dataFile.getType() != null && !dataFile.getType().trim().isEmpty()) {
dataOutputStream.writeBytes("Content-Type: " + dataFile.getType() + lineEnd);
}
dataOutputStream.writeBytes(lineEnd);
ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dataFile.getContent());
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1024 * 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dataOutputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
dataOutputStream.writeBytes(lineEnd);
}
/**
* Simple data container use for passing byte file
*/
public class DataPart {
private String fileName;
private byte[] content;
private String type;
/**
* Default data part
*/
public DataPart() {
}
/**
* Constructor with data.
*
* #param name label of data
* #param data byte data
*/
public DataPart(String name, byte[] data) {
fileName = name;
content = data;
}
/**
* Constructor with mime data type.
*
* #param name label of data
* #param data byte data
* #param mimeType mime data like "image/jpeg"
*/
public DataPart(String name, byte[] data, String mimeType) {
fileName = name;
content = data;
type = mimeType;
}
/**
* Getter file name.
*
* #return file name
*/
public String getFileName() {
return fileName;
}
/**
* Setter file name.
*
* #param fileName string file name
*/
public void setFileName(String fileName) {
this.fileName = fileName;
}
/**
* Getter content.
*
* #return byte file data
*/
public byte[] getContent() {
return content;
}
/**
* Setter content.
*
* #param content byte file data
*/
public void setContent(byte[] content) {
this.content = content;
}
/**
* Getter mime type.
*
* #return mime type
*/
public String getType() {
return type;
}
/**
* Setter mime type.
*
* #param type mime type
*/
public void setType(String type) {
this.type = type;
}
}
}
You can implement in activity or fragment like this
private void saveDoctorProfile(final String doctorId, final String firstName, final String lastName) {
showDialog();
VolleyMultipartRequest multipartRequest = new VolleyMultipartRequest(Request.Method.POST, AppConfig.LIVE_API_LINK + "getDoctorProfilePersonalinfo"
, new Response.Listener<NetworkResponse>() {
#Override
public void onResponse(NetworkResponse response) {
closeDialog();
String resultResponse = new String(response.data);
Log.d("doctor_profile_save", resultResponse);
try {
JSONObject result = new JSONObject(resultResponse);
AlertDialogManager.showSuccessDialog(getActivity(), "Your Personal Information saved successfully");
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
closeDialog();
NetworkResponse networkResponse = error.networkResponse;
String errorMessage = "Unknown error";
if (networkResponse == null) {
if (error.getClass().equals(TimeoutError.class)) {
errorMessage = "Request timeout";
} else if (error.getClass().equals(NoConnectionError.class)) {
errorMessage = "Failed to connect server";
}
} else {
String result = new String(networkResponse.data);
try {
JSONObject response = new JSONObject(result);
String status = response.getString("status");
String message = response.getString("message");
Log.e("Error Status", status);
Log.e("Error Message", message);
if (networkResponse.statusCode == 404) {
errorMessage = "Resource not found";
} else if (networkResponse.statusCode == 401) {
errorMessage = message + " Please login again";
} else if (networkResponse.statusCode == 400) {
errorMessage = message + " Check your inputs";
} else if (networkResponse.statusCode == 500) {
errorMessage = message + " Something is getting wrong";
}
} catch (JSONException e) {
e.printStackTrace();
}
}
Log.i("Error", errorMessage);
error.printStackTrace();
}
}) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("dri_drid", doctorId);
params.put("first_name", firstName);
params.put("last_name", lastName);
return params;
}
#Override
protected Map<String, DataPart> getByteData() {
Map<String, DataPart> params = new HashMap<>();
// file name could found file base or direct access from real path
// for now just get bitmap data from ImageView
params.put("image", new DataPart("file_avatar.jpg", AppHelper.getFileDataFromDrawable(getActivity(), ivPatientProfile.getDrawable()), "image/jpeg"));
return params;
}
};
AppController.getInstance().addToRequestQueue(multipartRequest);
}
I have an image and I want to upload this image to my web service using Volley library, the problem is I'm looking for a how to do it but still haven't found.
I am trying to upload image with Volley Multipart Request but I am not get success response from server but when I upload image using postman it's return success. This is my postman screenshot.
I search relate this but not get any idea.
below is my code
private void uploadMedia(final String token) {
VolleyMultipartRequest volleyMultipartRequest = new VolleyMultipartRequest(Request.Method.POST, upload_image,
new Response.Listener<NetworkResponse>() {
#Override
public void onResponse(NetworkResponse response) {
// iv_imageview.setImageBitmap(bitmap);
Log.e("VolleyOnResponse200", response.toString());
try {
JSONObject obj = new JSONObject(new String(response.data));
Log.e("response",obj+"");
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#SuppressLint("LongLogTag")
#Override
public void onErrorResponse(VolleyError error) {
Log.e("VolleyonErrorResponse200", "Error: " + error.getMessage());
// Toasty.error(getApplicationContext(),"Something went wrong", Toast.LENGTH_SHORT).show();
NetworkResponse response = error.networkResponse;
if (error instanceof ServerError && response != null) {
try {
String res = new String(response.data,
HttpHeaderParser.parseCharset(response.headers, "utf-8"));
// Now you can use any deserializer to make sense of data
JSONObject obj = new JSONObject(res);
} catch (UnsupportedEncodingException e1) {
// Couldn't properly decode data to string
e1.printStackTrace();
} catch (JSONException e2) {
// returned data is not JSONObject?
e2.printStackTrace();
}
}
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Content-Type", "application/json; charset=UTF-8");
params.put("Authorization", "bearer " + token);
return params;
}
#Override
protected Map<String, DataPart> getByteData() {
Map<String, DataPart> params = new HashMap<>();
long imagename = System.currentTimeMillis();
params.put("image", new DataPart(imagename + ".jpg", getFileDataFromDrawable(bitmap)));
return params;
}
};
volleyMultipartRequest.setRetryPolicy(new DefaultRetryPolicy(
999999999,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
//adding the request to volley
Volley.newRequestQueue(this).add(volleyMultipartRequest);
}
public byte[] getFileDataFromDrawable(Bitmap bitmap) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 80, byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
This is my VolleyMultipartRequest class
public class VolleyMultipartRequest extends Request<NetworkResponse> {
private final String twoHyphens = "--";
private final String lineEnd = "\r\n";
private final String boundary = "apiclient-" + System.currentTimeMillis();
private Response.Listener<NetworkResponse> mListener;
private Response.ErrorListener mErrorListener;
private Map<String, String> mHeaders;
public VolleyMultipartRequest(int method, String url,
Response.Listener<NetworkResponse> listener,
Response.ErrorListener errorListener) {
super(method, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
return (mHeaders != null) ? mHeaders : super.getHeaders();
}
#Override
public String getBodyContentType() {
return "multipart/form-data;boundary=" + boundary;
}
#Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
try {
// populate text payload
Map<String, String> params = getParams();
if (params != null && params.size() > 0) {
textParse(dos, params, getParamsEncoding());
}
// populate data byte payload
Map<String, DataPart> data = getByteData();
if (data != null && data.size() > 0) {
dataParse(dos, data);
}
// close multipart form data after text and file data
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* Custom method handle data payload.
*
* #return Map data part label with data byte
* #throws AuthFailureError
*/
protected Map<String, DataPart> getByteData() throws AuthFailureError {
return null;
}
#Override
protected Response<NetworkResponse> parseNetworkResponse(NetworkResponse response) {
try {
return Response.success(
response,
HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
return Response.error(new ParseError(e));
}
}
#Override
protected void deliverResponse(NetworkResponse response) {
mListener.onResponse(response);
}
#Override
public void deliverError(VolleyError error) {
mErrorListener.onErrorResponse(error);
}
/**
* Parse string map into data output stream by key and value.
*
* #param dataOutputStream data output stream handle string parsing
* #param params string inputs collection
* #param encoding encode the inputs, default UTF-8
* #throws IOException
*/
private void textParse(DataOutputStream dataOutputStream, Map<String, String> params, String encoding) throws IOException {
try {
for (Map.Entry<String, String> entry : params.entrySet()) {
buildTextPart(dataOutputStream, entry.getKey(), entry.getValue());
}
} catch (UnsupportedEncodingException uee) {
throw new RuntimeException("Encoding not supported: " + encoding, uee);
}
}
/**
* Parse data into data output stream.
*
* #param dataOutputStream data output stream handle file attachment
* #param data loop through data
* #throws IOException
*/
private void dataParse(DataOutputStream dataOutputStream, Map<String, DataPart> data) throws IOException {
for (Map.Entry<String, DataPart> entry : data.entrySet()) {
buildDataPart(dataOutputStream, entry.getValue(), entry.getKey());
}
}
/**
* Write string data into header and data output stream.
*
* #param dataOutputStream data output stream handle string parsing
* #param parameterName name of input
* #param parameterValue value of input
* #throws IOException
*/
private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
dataOutputStream.writeBytes(lineEnd);
dataOutputStream.writeBytes(parameterValue + lineEnd);
}
/**
* Write data file into header and data output stream.
*
* #param dataOutputStream data output stream handle data parsing
* #param dataFile data byte as DataPart from collection
* #param inputName name of data input
* #throws IOException
*/
private void buildDataPart(DataOutputStream dataOutputStream, DataPart dataFile, String inputName) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" +
inputName + "\"; filename=\"" + dataFile.getFileName() + "\"" + lineEnd);
if (dataFile.getType() != null && !dataFile.getType().trim().isEmpty()) {
dataOutputStream.writeBytes("Content-Type: " + dataFile.getType() + lineEnd);
}
dataOutputStream.writeBytes(lineEnd);
ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dataFile.getContent());
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1024 * 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dataOutputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
dataOutputStream.writeBytes(lineEnd);
}
public class DataPart {
private String fileName;
private byte[] content;
private String type;
public DataPart(String selectedPath, String path) {
}
public DataPart(String name, byte[] data) {
fileName = name;
content = data;
}
String getFileName() {
return fileName;
}
byte[] getContent() {
return content;
}
String getType() {
return type;
}
}
}
see below code I think there is problem
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Content-Type", "application/json; charset=UTF-8");
params.put("Authorization", "bearer " + token);
return params;
}
please comment below line
params.put("Content-Type", "application/json; charset=UTF-8");
This will help you
I'm just beginner in Android App development.
I want to upload image files using Android Volley library.
I have used this helper class found somewhere in some blog.:
public class VolleyMultiPartRequest extends Request<NetworkResponse> {
private final String twoHyphens = "--";
private final String lineEnd = "\r\n";
private final String boundary = "apiclient-" + System.currentTimeMillis();
private Response.Listener<NetworkResponse> mListener;
private Response.ErrorListener mErrorListener;
private Map<String, String> mHeaders;
SharedPreferencesManager sharedPreferencesManager =null;
public VolleyMultiPartRequest(int method, String url,
Response.Listener<NetworkResponse> listener,
Response.ErrorListener errorListener, Context context) {
super(method, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
this.sharedPreferencesManager = new SharedPreferencesManager(context);
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new HashMap<String, String>();
headers.put("Accept", "application/json");
headers.put("Authorization", "Bearer " + sharedPreferencesManager.retreiveString(AppText.ACCESS_TOKEN));
headers.put("Content-Type", "multipart/form-data");
return headers;
}
#Override
public String getBodyContentType() {
return "multipart/form-data;boundary=" + boundary;
}
#Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
try {
// populate text payload
Map<String, String> params = getParams();
if (params != null && params.size() > 0) {
textParse(dos, params, getParamsEncoding());
}
// populate data byte payload
Map<String, DataPart> data = getByteData();
if (data != null && data.size() > 0) {
dataParse(dos, data);
}
// close multipart form data after text and file data
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected Map<String, DataPart> getByteData() throws AuthFailureError {
return null;
}
#Override
protected Response<NetworkResponse> parseNetworkResponse(NetworkResponse response) {
try {
return Response.success(
response,
HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
return Response.error(new ParseError(e));
}
}
#Override
protected void deliverResponse(NetworkResponse response) {
mListener.onResponse(response);
}
#Override
public void deliverError(VolleyError error) {
mErrorListener.onErrorResponse(error);
}
private void textParse(DataOutputStream dataOutputStream, Map<String, String> params, String encoding) throws IOException {
try {
for (Map.Entry<String, String> entry : params.entrySet()) {
buildTextPart(dataOutputStream, entry.getKey(), entry.getValue());
}
} catch (UnsupportedEncodingException uee) {
throw new RuntimeException("Encoding not supported: " + encoding, uee);
}
}
private void dataParse(DataOutputStream dataOutputStream, Map<String, DataPart> data) throws IOException {
for (Map.Entry<String, DataPart> entry : data.entrySet()) {
buildDataPart(dataOutputStream, entry.getValue(), entry.getKey());
}
}
private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
dataOutputStream.writeBytes(lineEnd);
dataOutputStream.writeBytes(parameterValue + lineEnd);
}
private void buildDataPart(DataOutputStream dataOutputStream, DataPart dataFile, String inputName) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" +
inputName + "\"; filename=\"" + dataFile.getFileName() + "\"" + lineEnd);
if (dataFile.getType() != null && !dataFile.getType().trim().isEmpty()) {
dataOutputStream.writeBytes("Content-Type: " + dataFile.getType() + lineEnd);
}
dataOutputStream.writeBytes(lineEnd);
ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dataFile.getContent());
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1024 * 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dataOutputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
dataOutputStream.writeBytes(lineEnd);
}
public class DataPart {
private String fileName;
private byte[] content;
private String type;
public DataPart() {
}
public DataPart(String name, byte[] data) {
fileName = name;
content = data;
}
String getFileName() {
return fileName;
}
byte[] getContent() {
return content;
}
String getType() {
return type;
}
}
}
And called this helper like this:
VolleyMultiPartRequest volleyMultipartRequest = new VolleyMultiPartRequest(Request.Method.POST, Api.UPLOAD_FILE,
new Response.Listener<NetworkResponse>() {
#Override
public void onResponse(NetworkResponse response) {
try {
JSONObject obj = new JSONObject(new String(response.data));
Toast.makeText(context, obj.getString("message"), Toast.LENGTH_SHORT).show();
successCallBack.onSuccess(obj);
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(context, error.getMessage(), Toast.LENGTH_SHORT).show();
try {
errorCallBack.onError(new JSONObject(""));
} catch (JSONException e) {
e.printStackTrace();
}
}
}, context) {
/*
* If you want to add more parameters with the image
* you can do it here
* here we have only one parameter with the image
* which is tags
* */
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("file_for", "post");
params.put("file_type", "image");
return params;
}
/*
* Here we are passing image by renaming it with a unique name
* */
#Override
protected Map<String, DataPart> getByteData() {
Map<String, DataPart> params = new HashMap<>();
long imagename = System.currentTimeMillis();
params.put("images[]", new DataPart(imagename + ".png", getFileDataFromDrawable(bitmap)));
return params;
}
};
I'm getting server error as a response.
I tried different tutorials but didn't find the exact way and easy solution.
In the postman, headers and params are like this, there are an array of images, you can see in photos attached (8 photos). I want to do exact same API call using volley library.
Try this code:
I had similar kind of issue i fixed using this
Uploading multiple files in array using multipart
Add dependecies
compile 'org.apache.httpcomponents:httpcore:4.2.4'
compile 'org.apache.httpcomponents:httpmime:4.2'
compile 'com.mcxiaoke.volley:library:1.0.19'
2.Add in gradle
defaultConfig {
useLibrary 'org.apache.http.legacy'
}
Helper class AndroidMultiPartEntity.java
public class AndroidMultiPartEntity extends MultipartEntity
{
private final ProgressListener listener;
public AndroidMultiPartEntity(final ProgressListener listener) {
super();
this.listener = listener;
}
public AndroidMultiPartEntity(final HttpMultipartMode mode, final ProgressListener listener) {
super(mode);
this.listener = listener;
}
public AndroidMultiPartEntity(HttpMultipartMode mode, final String boundary,
final Charset charset, final ProgressListener listener) {
super(mode, boundary, charset);
this.listener = listener;
}
#Override
public void writeTo(final OutputStream outstream) throws IOException {
super.writeTo(new CountingOutputStream(outstream, this.listener));
}
public interface ProgressListener {
void transferred(long num);
}
public static class CountingOutputStream extends FilterOutputStream {
private final ProgressListener listener;
private long transferred;
public CountingOutputStream(final OutputStream out,
final ProgressListener listener) {
super(out);
this.listener = listener;
this.transferred = 0;
}
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
this.transferred += len;
this.listener.transferred(this.transferred);
}
public void write(int b) throws IOException {
out.write(b);
this.transferred++;
this.listener.transferred(this.transferred);
}
}
}
API call method
private class registerCall extends AsyncTask<Void, Integer, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onProgressUpdate(Integer... progress) {
}
#Override
protected String doInBackground(Void... params) {
return registerMultipartCall();
}
private String registerMultipartCall() {
String responseString = null;
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("URL"); //UPLOAD URL
try {
AndroidMultiPartEntity entity = new AndroidMultiPartEntity(new AndroidMultiPartEntity.ProgressListener() {
#Override
public void transferred(long num) {
}
});
File sourceFile = new File(filePath);
File sourceFile2 = new File(filePath);
entity.addPart("images[0]", new FileBody(sourceFile));
entity.addPart("images[1]", new FileBody(sourceFile2));
//Do your stuff multiple files
entity.addPart("file_type", new StringBody("image");
entity.addPart("file_form", new StringBody("post");
httppost.addHeader("Accept","application/json");
httppost.addHeader("Content-Type", "multipart/form-data");
httppost.addHeader("Authorization", "Bearer " + sharedPreferencesManager.retreiveString(AppText.ACCESS_TOKEN));
httppost.setEntity(entity);
// Making server call
HttpResponse response = httpclient.execute(httppost);
HttpEntity r_entity = response.getEntity();
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
// Server response
statusCode = 200;
responseString = EntityUtils.toString(r_entity);
} else {
statusCode = 200;
responseString = "Error occurred! Http Status Code: " + statusCode;
}
} catch (ClientProtocolException e) {
responseString = e.toString();
} catch (IOException e) {
responseString = e.toString();
}
return responseString;
}
#Override
protected void onPostExecute(String result) {
hideProgressDialog();
}
}
5.Calling Async
new registerCall().execute();
Just replace getByteData() method with this below code:
private dataPartList = ArrayList();
#Override
protected Map<String, List<DataPart>> getByteDataList(){
Map<String, List<DataPart>> params = new HashMap<>();
params.put("yourKey","dataPartList");
return params
}
This is the gist iam refering for uploading images to the server https://gist.github.com/anggadarkprince/a7c536da091f4b26bb4abf2f92926594
But iam using TedPicker OnMultiImageSelectedListener to select multiple images https://android-arsenal.com/details/1/4320
It gives me selectedUriList in an ArrayLIst . I convert all the Uri's to byteArray and upload to server.
Here is my Code of Uploading Image .
private void imageUpload() {
final ProgressDialog loading = ProgressDialog.show(this,"Uploading...","Please wait...",false,false);
VolleyMultipartRequest multipartRequest = new VolleyMultipartRequest(Request.Method.POST, Constants.UPLOAD_URL, new Response.Listener<NetworkResponse>() {
#Override
public void onResponse(NetworkResponse response) {
String resultResponse = new String(response.data);
try {
JSONObject result = new JSONObject(resultResponse);
String status = result.getString("status");
String message = result.getString("message");
loading.dismiss();
if (status.equals(Constants.REQUEST_SUCCESS)) {
// tell everybody you have succed upload image and post strings
Log.i("Messsage", message);
} else {
Log.i("Unexpected", message);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
loading.dismiss();
NetworkResponse networkResponse = error.networkResponse;
String errorMessage = "Unknown error";
if (networkResponse == null) {
if (error.getClass().equals(TimeoutError.class)) {
errorMessage = "Request timeout";
} else if (error.getClass().equals(NoConnectionError.class)) {
errorMessage = "Failed to connect server";
}
} else {
String result = new String(networkResponse.data);
try {
JSONObject response = new JSONObject(result);
String status = response.getString("status");
String message = response.getString("message");
Log.e("Error Status", status);
Log.e("Error Message", message);
if (networkResponse.statusCode == 404) {
errorMessage = "Resource not found";
} else if (networkResponse.statusCode == 401) {
errorMessage = message+" Please login again";
} else if (networkResponse.statusCode == 400) {
errorMessage = message+ " Check your inputs";
} else if (networkResponse.statusCode == 500) {
errorMessage = message+" Something is getting wrong";
}
} catch (JSONException e) {
e.printStackTrace();
}
}
Log.i("Error", errorMessage);
}
}) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("folder_name", FOLDER_NAME);
return params;
}
#Override
protected Map<String, DataPart> getByteData() {
Map<String, DataPart> params = new HashMap<>();
int i = 0;
for (Uri uri : selectedUriList) {
i++;
try {
InputStream iStream = getContentResolver().openInputStream(uri);
byte[] inputData = getBytes(iStream);
params.put("image_file"+i, new DataPart("image"+i+".jpg", inputData , "image/jpeg"));
} catch (IOException e) {
e.printStackTrace();
}
}
return params;
}
};
VolleySingleton.getInstance(getBaseContext()).addToRequestQueue(multipartRequest);
}
public byte[] getBytes(InputStream inputStream) throws IOException {
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int len = 0;
while ((len = inputStream.read(buffer)) != -1) {
byteBuffer.write(buffer, 0, len);
}
return byteBuffer.toByteArray();
}
The error iam facing while trying to upload image
I/System.out: [socket]rx timeout:2500
I/System.out: [socket][0] connection ascentcity.com/119.81.195.196:80;LocalPort=45296(2500)
I/System.out: [CDS]connect[ascentcity.com/119.81.195.196:80] tm:2
D/Posix: [Posix_connect Debug]Process com.vst.image.vehiclestimageclassifier :80
I/System.out: [socket][/192.168.31.42:45296] connected
I/System.out: [socket]rx timeout:2500
D/Volley: [22832] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] http://ascentcity.com/Mobileapp/upload.php 0x43980958 NORMAL 1> [lifetime=48143], [size=116], [rc=200], [retryCount=0]
W/System.err: org.json.JSONException: Value Sorry of type java.lang.String cannot be converted to JSONObject
W/System.err: at org.json.JSON.typeMismatch(JSON.java:111)
W/System.err: at org.json.JSONObject.<init>(JSONObject.java:160)
W/System.err: at org.json.JSONObject.<init>(JSONObject.java:173)
W/System.err: at com.vst.image.vehiclestimageclassifier.MainActivity$3.onResponse(MainActivity.java:171)
W/System.err: at com.vst.image.vehiclestimageclassifier.MainActivity$3.onResponse(MainActivity.java:166)
W/System.err: at com.vst.image.vehiclestimageclassifier.VolleyMultipartRequest.deliverResponse(VolleyMultipartRequest.java:127)
W/System.err: at com.vst.image.vehiclestimageclassifier.VolleyMultipartRequest.deliverResponse(VolleyMultipartRequest.java:24)
W/System.err: at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:99)
W/System.err: at android.os.Handler.handleCallback(Handler.java:739)
W/System.err: at android.os.Handler.dispatchMessage(Handler.java:95)
W/System.err: at android.os.Looper.loop(Looper.java:157)
W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5429)
W/System.err: at java.lang.reflect.Method.invoke(Native Method)
W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
I have a few questions
Is it okay to retrive byte data from images like this or there are better ways ?
#Override
protected Map<String, DataPart> getByteData() {
Map<String, DataPart> params = new HashMap<>();
int i = 0;
for (Uri uri : selectedUriList) {
i++;
try {
InputStream iStream = getContentResolver().openInputStream(uri);
byte[] inputData = getBytes(iStream);
// file name could found file base or direct access from real path
// for now just get bitmap data from ImageView
params.put("image_file"+i, new DataPart("image"+i+".jpg", inputData , "image/jpeg"));
} catch (IOException e) {
e.printStackTrace();
}
}
return params;
}
The error iam facing is due to slow server ? or something else ? how to debug this?
Is there something i need to communicate to backend team (Server Side) , imean to handle my request .
Here is the github link to complete project code https://github.com/sooorajjj/vstImageClassifier
Thanks!
Here is my customised VolleyMultipartRequest file. You may use it directly for uploading multiple images in same parameter name :
import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.HttpHeaderParser;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Map;
/**
* Custom request to make multipart header and upload file.
* <p>
* Sketch Project Studio
* Created by bhuvnesh 8/10/2019
*/
#SuppressWarnings("unused")
public class VolleyMultipartRequest extends Request<JSONObject> {
private final String twoHyphens = "--";
private final String lineEnd = "\r\n";
private final String boundary = "apiclient-" + System.currentTimeMillis();
private Response.Listener<JSONObject> mListener;
private Response.ErrorListener mErrorListener;
private Map<String, String> mHeaders;
public VolleyMultipartRequest(String url, Map<String, String> headers,
Response.Listener<JSONObject> listener,
Response.ErrorListener errorListener) {
super(Method.POST, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
this.mHeaders = headers;
}
public VolleyMultipartRequest(int method, String url,
Response.Listener<JSONObject> listener,
Response.ErrorListener errorListener) {
super(method, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
return (mHeaders != null) ? mHeaders : super.getHeaders();
}
#Override
public String getBodyContentType() {
return "multipart/form-data;boundary=" + boundary;
}
#Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
try {
// populate text payload
Map<String, String> params = getParams();
if (params != null && params.size() > 0) {
textParse(dos, params, getParamsEncoding());
}
// populate data byte payload
Map<String, ArrayList<DataPart>> data = getByteData();
if (data != null && data.size() > 0) {
dataParse(dos, data);
}
// close multipart form data after text and file data
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected Map<String, ArrayList<DataPart>> getByteData() throws AuthFailureError {
return null;
}
#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) {
mListener.onResponse(response);
}
#Override
public void deliverError(VolleyError error) {
mErrorListener.onErrorResponse(error);
}
private void textParse(DataOutputStream dataOutputStream, Map<String, String> params, String encoding) throws IOException {
try {
for (Map.Entry<String, String> entry : params.entrySet()) {
buildTextPart(dataOutputStream, entry.getKey(), entry.getValue());
}
} catch (UnsupportedEncodingException uee) {
throw new RuntimeException("Encoding not supported: " + encoding, uee);
}
}
private void dataParse(DataOutputStream dataOutputStream, Map<String, ArrayList<DataPart>> data) throws IOException {
for (Map.Entry<String, ArrayList<DataPart>> entry : data.entrySet()) {
buildDataPart(dataOutputStream, entry.getValue(), entry.getKey());
}
}
private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
//dataOutputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd);
dataOutputStream.writeBytes(lineEnd);
dataOutputStream.writeBytes(parameterValue + lineEnd);
}
private void buildDataPart(DataOutputStream dataOutputStream, ArrayList<DataPart> dataFile, String inputName) throws IOException {
for (int i=0; i<dataFile.size(); i++){
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
DataPart dp = dataFile.get(i);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" +
inputName + "\"; filename=\"" + dp.getFileName() + "\"" + lineEnd);
if (dp.getType() != null && !dp.getType().trim().isEmpty()) {
dataOutputStream.writeBytes("Content-Type: " + dp.getType() + lineEnd);
}
dataOutputStream.writeBytes(lineEnd);
ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dp.getContent());
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1024 * 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dataOutputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
dataOutputStream.writeBytes(lineEnd);
}
}
public class DataPart {
private String fileName;
private byte[] content;
private String type;
public DataPart() {
}
public DataPart(String name, byte[] data) {
fileName = name;
content = data;
}
public DataPart(String name, byte[] data, String mimeType) {
fileName = name;
content = data;
type = mimeType;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public byte[] getContent() {
return content;
}
public void setContent(byte[] content) {
this.content = content;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
}
And here is code to use this volleyMultipartRequest file :
VolleyMultipartRequest multipartRequest = new VolleyMultipartRequest(Request.Method.POST,
BaseURL.ADD_INVOICE, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
Toast.makeText(HomeActivity.this, response.getString("message"), Toast.LENGTH_LONG).show();
if (response.getString("message").equals("Invoice added successfully!!")){
check=true;
Intent intent = new Intent(HomeActivity.this, ThankyouActivity.class);
startActivity(intent);
//finish();
}else {
Toast.makeText(HomeActivity.this, response.getString("message"), Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
progressdialog.dismisswaitdialog();
if (error instanceof TimeoutError || error instanceof NoConnectionError) {
Toast.makeText(HomeActivity.this, getResources().getString(R.string.connection_time_out), Toast.LENGTH_SHORT).show();
}
}
}) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("user_id", user_id);
params.put("year", et_year.getText().toString());
params.put("make", et_make.getText().toString());
params.put("model", et_model.getText().toString());
return params;
}
#Override
protected Map<String, ArrayList<DataPart>> getByteData() {
Map<String, VolleyMultipartRequest.DataPart> params = new HashMap<>();
Map<String, ArrayList<DataPart>> imageList = new HashMap<>();
ArrayList<DataPart> dataPart = new ArrayList<>();
String imagename = "image[]";
for (int i=0; i<encodedImageList.size(); i++){
VolleyMultipartRequest.DataPart dp = new VolleyMultipartRequest.DataPart(imagename+i, Base64.decode(encodedImageList.get(i), Base64.DEFAULT), "image/jpeg");
dataPart.add(dp);
//params.put(imagename, new DataPart(imagename+i, Base64.decode(encodedImageList.get(i), Base64.DEFAULT), "image/jpeg"));
}
imageList.put("image[]", dataPart);
return imageList;
}
};
int socketTimeout = 500000;//30 seconds - change to what you want
RetryPolicy policy = new DefaultRetryPolicy(socketTimeout, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
multipartRequest.setRetryPolicy(policy);
AppController.getInstance().addToRequestQueue(multipartRequest);
For Kotlin use MutableMap<String,ArrayList<DataPart>> instead of Map<String,ArrayList<DataPart>>.
And should be initialize like this way.
val dataParts:MutableMap<String,ArrayList<DataPart>> = mutableMapOf()
And put the data same as HashMap<K,V>.
I have data in byte array, I need to send it to the service from Volley library. This is what i tried but its not reaching on the getBody() method, and returns response before reading body,
StringRequest stringRequest = new StringRequest(Request.Method.GET, URL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d("Success", response.toString());
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("Error", error.toString());
}
}){
#Override
public byte[] getBody() throws AuthFailureError {
return bytesObject;
}
#Override
public String getBodyContentType() {
return "application/json; charset=utf-8";
}
};
RequestQueue requestQueue = Volley.newRequestQueue(AnalyticsApplication.getAppContext());
requestQueue.add(stringRequest);
May be i am missing something, Kindly guide me how to send byte array from Volley library.
try this
public void actionCallWebServiceWithFiles(String url, final HashMap<String, String> params, final Map<String, VolleyMultipartRequest.DataPart> file) {
VolleyMultipartRequest multipartRequest = new VolleyMultipartRequest(Request.Method.POST, url, new Response.Listener<NetworkResponse>() {
#Override
public void onResponse(NetworkResponse response) {
String resultResponse = new String(response.data);
try {
JSONObject result = new JSONObject(resultResponse);
/*String status = result.getString("status");
String message = result.getString("message");
if (status.equals(Constants.SUCCESS)) {
// tell everybody you have succed upload image and post strings
Log.i("Messsage", message);
} else {
Log.i("Unexpected", message);
}*/
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
NetworkResponse networkResponse = error.networkResponse;
String errorMessage = "Unknown error";
if (networkResponse == null) {
if (error.getClass().equals(TimeoutError.class)) {
errorMessage = "Request timeout";
} else if (error.getClass().equals(NoConnectionError.class)) {
errorMessage = "Failed to connect server";
}
} else {
String result = new String(networkResponse.data);
try {
JSONObject response = new JSONObject(result);
String status = response.getString("status");
String message = response.getString("message");
Log.e("Error Status", status);
Log.e("Error Message", message);
if (networkResponse.statusCode == 404) {
errorMessage = "Resource not found";
} else if (networkResponse.statusCode == 401) {
errorMessage = message + " Please login again";
} else if (networkResponse.statusCode == 400) {
errorMessage = message + " Check your inputs";
} else if (networkResponse.statusCode == 500) {
errorMessage = message + " Something is getting wrong";
}
} catch (JSONException e) {
e.printStackTrace();
}
}
Log.i("Error", errorMessage);
error.printStackTrace();
}
}, onProgressUpdate) {
#Override
protected Map<String, String> getParams() {
return params;
}
#Override
protected Map<String, DataPart> getByteData() {
Map<String, DataPart> params = new HashMap<>();
// file name could found file base or direct access from real path
// for now just get bitmap data from ImageView
// params.put("doc_file", new DataPart("file_avatar.jpg", Common.getFileDataFromDrawable(context, context.getDrawable(R.drawable.ic_app_icon)), "image/png"));
// params.put("upload_file", new DataPart("screens.zip",file,"application/zip"));
return file;
}
};
MyApplication.getInstance().addToRequestQueue(multipartRequest);
}
VolleyMultiPartRequest.java
public class VolleyMultipartRequest extends Request<NetworkResponse> {
private final String twoHyphens = "--";
private final String lineEnd = "\r\n";
private final String boundary = "apiclient-" + System.currentTimeMillis();
private Response.Listener<NetworkResponse> mListener;
private Response.ErrorListener mErrorListener;
private Map<String, String> mHeaders;
private OnProgressUpdate onProgressUpdate;
private int transferred = 0;
/**
* Default constructor with predefined header and post method.
*
* #param url request destination
* #param headers predefined custom header
* #param listener on success achieved 200 code from request
* #param errorListener on error http or library timeout
*/
public VolleyMultipartRequest(String url, Map<String, String> headers,
Response.Listener<NetworkResponse> listener,
Response.ErrorListener errorListener) {
super(Method.POST, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
this.mHeaders = headers;
}
/**
* Constructor with option method and default header configuration.
*
* #param method method for now accept POST and GET only
* #param url request destination
* #param listener on success event handler
* #param errorListener on error event handler
*/
public VolleyMultipartRequest(int method, String url,
Response.Listener<NetworkResponse> listener,
Response.ErrorListener errorListener, OnProgressUpdate onProgressUpdate) {
super(method, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
this.onProgressUpdate = onProgressUpdate;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
return (mHeaders != null) ? mHeaders : super.getHeaders();
}
#Override
public String getBodyContentType() {
return "multipart/form-data;boundary=" + boundary;
}
#Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
try {
// populate text payload
Map<String, String> params = getParams();
if (params != null && params.size() > 0) {
textParse(dos, params, getParamsEncoding());
}
// populate data byte payload
Map<String, DataPart> data = getByteData();
if (data != null && data.size() > 0) {
dataParse(dos, data);
}
// close multipart form data after text and file data
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* Custom method handle data payload.
*
* #return Map data part label with data byte
* #throws AuthFailureError
*/
protected Map<String, DataPart> getByteData() throws AuthFailureError {
return null;
}
#Override
protected Response<NetworkResponse> parseNetworkResponse(NetworkResponse response) {
try {
return Response.success(
response,
HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
return Response.error(new ParseError(e));
}
}
#Override
protected void deliverResponse(NetworkResponse response) {
mListener.onResponse(response);
}
#Override
public void deliverError(VolleyError error) {
mErrorListener.onErrorResponse(error);
}
/**
* Parse string map into data output stream by key and value.
*
* #param dataOutputStream data output stream handle string parsing
* #param params string inputs collection
* #param encoding encode the inputs, default UTF-8
* #throws IOException
*/
private void textParse(DataOutputStream dataOutputStream, Map<String, String> params, String encoding) throws IOException {
try {
for (Map.Entry<String, String> entry : params.entrySet()) {
buildTextPart(dataOutputStream, entry.getKey(), entry.getValue());
}
} catch (UnsupportedEncodingException uee) {
throw new RuntimeException("Encoding not supported: " + encoding, uee);
}
}
/**
* Parse data into data output stream.
*
* #param dataOutputStream data output stream handle file attachment
* #param data loop through data
* #throws IOException
*/
private void dataParse(DataOutputStream dataOutputStream, Map<String, DataPart> data) throws IOException {
for (Map.Entry<String, DataPart> entry : data.entrySet()) {
buildDataPart(dataOutputStream, entry.getValue(), entry.getKey());
}
}
/**
* Write string data into header and data output stream.
*
* #param dataOutputStream data output stream handle string parsing
* #param parameterName name of input
* #param parameterValue value of input
* #throws IOException
*/
private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
//dataOutputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd);
dataOutputStream.writeBytes(lineEnd);
dataOutputStream.writeBytes(parameterValue + lineEnd);
}
/**
* Write data file into header and data output stream.
*
* #param dataOutputStream data output stream handle data parsing
* #param dataFile data byte as DataPart from collection
* #param inputName name of data input
* #throws IOException
*/
private void buildDataPart(DataOutputStream dataOutputStream, DataPart dataFile, String inputName) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" +
inputName + "\"; filename=\"" + dataFile.getFileName() + "\"" + lineEnd);
if (dataFile.getType() != null && !dataFile.getType().trim().isEmpty()) {
dataOutputStream.writeBytes("Content-Type: " + dataFile.getType() + lineEnd);
}
dataOutputStream.writeBytes(lineEnd);
ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dataFile.getContent());
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1024 * 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
long total = 0;
while (bytesRead > 0) {
dataOutputStream.write(buffer, 0, bufferSize);
total = dataOutputStream.size();
transferred = (int) (total * 100 / dataFile.getContent().length) ;
onProgressUpdate.onTransferred(transferred);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
dataOutputStream.writeBytes(lineEnd);
}
/**
* Simple data container use for passing byte file
*/
public static class DataPart {
private String fileName;
private byte[] content;
private String type;
/**
* Default data part
*/
public DataPart() {
}
/**
* Constructor with data.
*
* #param name label of data
* #param data byte data
*/
public DataPart(String name, byte[] data) {
fileName = name;
content = data;
}
/**
* Constructor with mime data type.
*
* #param name label of data
* #param data byte data
* #param mimeType mime data like "image/jpeg"
*/
public DataPart(String name, byte[] data, String mimeType) {
fileName = name;
content = data;
type = mimeType;
}
/**
* Getter file name.
*
* #return file name
*/
public String getFileName() {
return fileName;
}
/**
* Setter file name.
*
* #param fileName string file name
*/
public void setFileName(String fileName) {
this.fileName = fileName;
}
/**
* Getter content.
*
* #return byte file data
*/
public byte[] getContent() {
return content;
}
/**
* Setter content.
*
* #param content byte file data
*/
public void setContent(byte[] content) {
this.content = content;
}
/**
* Getter mime type.
*
* #return mime type
*/
public String getType() {
return type;
}
/**
* Setter mime type.
*
* #param type mime type
*/
public void setType(String type) {
this.type = type;
}
}
}