-
-
Save anggadarkprince/a7c536da091f4b26bb4abf2f92926594 to your computer and use it in GitHub Desktop.
import android.graphics.Bitmap; | |
import android.graphics.drawable.BitmapDrawable; | |
import android.graphics.drawable.Drawable; | |
import java.io.ByteArrayOutputStream; | |
/** | |
* Sketch Project Studio | |
* Created by Angga on 12/04/2016 14.27. | |
*/ | |
public class AppHelper { | |
/** | |
* Turn drawable resource into byte array. | |
* | |
* @param context parent context | |
* @param id drawable resource id | |
* @return byte array | |
*/ | |
public static byte[] getFileDataFromDrawable(Context context, int id) { | |
Drawable drawable = ContextCompat.getDrawable(context, id); | |
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); | |
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); | |
bitmap.compress(Bitmap.CompressFormat.PNG, 0, byteArrayOutputStream); | |
return byteArrayOutputStream.toByteArray(); | |
} | |
/** | |
* Turn drawable into byte array. | |
* | |
* @param drawable data | |
* @return byte array | |
*/ | |
public static byte[] getFileDataFromDrawable(Context context, Drawable drawable) { | |
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); | |
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); | |
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, byteArrayOutputStream); | |
return byteArrayOutputStream.toByteArray(); | |
} | |
} |
/** | |
* Sketch Project Studio | |
* Created by Angga 20/04/2016 19:32 | |
*/ | |
public class MainActivity extends AppCompatActivity { | |
private EditText mNameInput; | |
private EditText mLocationInput; | |
private EditText mAboutInput; | |
private EditText mContact; | |
private ImageView mAvatarImage; | |
private ImageView mCoverImage; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
mNameInput = (EditText) findViewById(R.id.input_name); | |
mLocationInput = (EditText) findViewById(R.id.input_location); | |
mAboutInput = (EditText) findViewById(R.id.input_about); | |
mContact = (EditText) findViewById(R.id.input_contact); | |
mAvatarImage = (ImageView) findViewById(R.id.avatar); | |
mCoverImage = (ImageView) findViewById(R.id.cover); | |
// do anything before post data.. or triggered after button clicked | |
saveProfileAccount(); | |
} | |
private void saveProfileAccount() { | |
// loading or check internet connection or something... | |
// ... then | |
String url = "http://www.angga-ari.com/api/something/awesome"; | |
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(Constant.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) { | |
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("api_token", "gh659gjhvdyudo973823tt9gvjf7i6ric75r76"); | |
params.put("name", mNameInput.getText().toString()); | |
params.put("location", mLocationInput.getText().toString()); | |
params.put("about", mAboutInput.getText().toString()); | |
params.put("contact", mContactInput.getText().toString()); | |
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("avatar", new DataPart("file_avatar.jpg", AppHelper.getFileDataFromDrawable(getBaseContext(), mAvatarImage.getDrawable()), "image/jpeg")); | |
params.put("cover", new DataPart("file_cover.jpg", AppHelper.getFileDataFromDrawable(getBaseContext(), mCoverImage.getDrawable()), "image/jpeg")); | |
return params; | |
} | |
}; | |
VolleySingleton.getInstance(getBaseContext()).addToRequestQueue(multipartRequest); | |
} | |
} |
package com.sketchproject.infogue.modules; | |
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. | |
* | |
* Sketch Project Studio | |
* Created by Angga on 27/04/2016 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; | |
} | |
} | |
} |
package com.sketchproject.infogue.modules; | |
import android.content.Context; | |
import android.graphics.Bitmap; | |
import android.support.v4.util.LruCache; | |
import com.android.volley.Request; | |
import com.android.volley.RequestQueue; | |
import com.android.volley.toolbox.ImageLoader; | |
import com.android.volley.toolbox.Volley; | |
/** | |
* Singleton volley to populate request into single queue. | |
* | |
* Sketch Project Studio | |
* Created by Angga on 22/04/2016 22.58. | |
*/ | |
public class VolleySingleton { | |
private static VolleySingleton mInstance; | |
private RequestQueue mRequestQueue; | |
private ImageLoader mImageLoader; | |
private static Context mCtx; | |
/** | |
* Private constructor, only initialization from getInstance. | |
* | |
* @param context parent context | |
*/ | |
private VolleySingleton(Context context) { | |
mCtx = context; | |
mRequestQueue = getRequestQueue(); | |
mImageLoader = new ImageLoader(mRequestQueue, | |
new ImageLoader.ImageCache() { | |
private final LruCache<String, Bitmap> cache = new LruBitmapCache(mCtx); | |
@Override | |
public Bitmap getBitmap(String url) { | |
return cache.get(url); | |
} | |
@Override | |
public void putBitmap(String url, Bitmap bitmap) { | |
cache.put(url, bitmap); | |
} | |
}); | |
} | |
/** | |
* Singleton construct design pattern. | |
* | |
* @param context parent context | |
* @return single instance of VolleySingleton | |
*/ | |
public static synchronized VolleySingleton getInstance(Context context) { | |
if (mInstance == null) { | |
mInstance = new VolleySingleton(context); | |
} | |
return mInstance; | |
} | |
/** | |
* Get current request queue. | |
* | |
* @return RequestQueue | |
*/ | |
public RequestQueue getRequestQueue() { | |
if (mRequestQueue == null) { | |
// getApplicationContext() is key, it keeps you from leaking the | |
// Activity or BroadcastReceiver if someone passes one in. | |
mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext()); | |
} | |
return mRequestQueue; | |
} | |
/** | |
* Add new request depend on type like string, json object, json array request. | |
* | |
* @param req new request | |
* @param <T> request type | |
*/ | |
public <T> void addToRequestQueue(Request<T> req) { | |
getRequestQueue().add(req); | |
} | |
/** | |
* Get image loader. | |
* | |
* @return ImageLoader | |
*/ | |
public ImageLoader getImageLoader() { | |
return mImageLoader; | |
} | |
} |
Thank You For this code.But i am getting this message.can any one help me.
if (status.equals(Constant.REQUEST_SUCCESS))
Error : Cannot resolve symbol
Getting an error in :
if (status.equals(Constant.REQUEST_SUCCESS))
Error : Cannot resolve symbolDo I need to create a "Constant" class?
replace "Constant.REQUEST_SUCCESS" that with the success message returned by your server
Bro, you're an actual lifesaver, I've looked everywhere for this, Such a clean and well-commented solution, you're amazing
Hey, thank you so much.
Just a minor correction:
at MainActivity.java, line 98
replace "mAvatarInput" with "mAboutInput"
"dataOutputStream.write(parameterValue.getBytes("utf-8"));"
"dataOutputStream.writeBytes(lineEnd);"
Thanks for the answer you saved my life...
@db0910 Thanks for your addition to VolleyMultipartRequest
Thank you! It works for me very well!
in class VolleySingleton.java
private final LruCache<String, Bitmap> cache = new LruBitmapCache(mCtx);
in this line i am getting error that
cannot resolve symbol LruBitmapCache
i am getting this in respnse, what could be the issue
com.android.volley.NetworkResponse@ed190b5
Thank you so much it's work for me
Hola amigo @anggadarkprince estoy tratando de adaptar la clase VolleyMultipart a una llamada VolleyArrayMultipart para poder subir un array de archivos. Te agradezco de antemano si podrías darme algunas indicaciones.