-
Star
(144)
You must be signed in to star a gist -
Fork
(65)
You must be signed in to fork a gist
-
-
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; | |
| } | |
| } |
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
replace "Constant.REQUEST_SUCCESS" that with the success message returned by your server