public class UploadsHandler { public static final int UPLOAD_LOADING = -1; public static final int UPLOAD_ABORTED = -2; public static final int UPLOAD_ERROR = -3; private static UploadsHandler ourInstance; private Context context; private volatile HashMap uploads; private List> uploadTempQueue; private final OkHttpClient client; private final Gson gson; private final Handler handler; public static UploadsHandler getInstance() { if (ourInstance == null) ourInstance = new UploadsHandler(Utils.getAppContext()); return ourInstance; } private UploadsHandler(Context context) { this.context = context; uploads = new HashMap<>(); uploadTempQueue = new ArrayList<>(); client = new OkHttpClient(); gson = new Gson(); handler = new Handler(context.getMainLooper()); } /** * Starts uploading an image to the server * * @param apiPath api URL; e.g. /api/userImage/upload/ * @param imagePath Path to the image on disk * @param tempId The temoporary name that the image gets until it's uploaded * @param callback Callback to be executed after the upload is finished */ public void uploadImage(String apiPath, String imagePath, final String tempId, final ApiCallback callback) { final UploadData uploadData = new UploadData(); uploadData.imagePath = imagePath; uploadData.progressValue = 0; uploadData.status = UPLOAD_LOADING; uploadData.apiMethod = apiPath; final File file = new File(imagePath); final long totalSize = file.length(); RequestBody requestBody = new MultipartBuilder() .type(MultipartBuilder.FORM) .addPart( Headers.of("Content-Disposition", "form-data; name=\"image\"; filename=\"" + file.getName() + "\""), new CountingFileRequestBody(file, "image/*", new CountingFileRequestBody.ProgressListener() { @Override public void transferred(long num) { float progress = (num / (float) totalSize) * 100; uploadData.progressValue = (int) progress; handler.post(new Runnable() { @Override public void run() { updateProgressBar(tempId); } }); } }) ) .build(); Request request = new Request.Builder() .tag(tempId) .url(Constants.BASE_URL + apiPath) .post(requestBody) .build(); uploads.put(tempId, uploadData); Call call = client.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(final Request request, IOException e) { if (Constants.DEV) { e.printStackTrace(); } uploads.get(tempId).progressValue = -1; if (uploadCanceled(tempId)) { uploads.get(tempId).status = UPLOAD_ABORTED; } else { uploads.get(tempId).status = UPLOAD_ERROR; } handler.post(new Runnable() { @Override public void run() { try { ErrorModel body = gson.fromJson(request.body().toString(), ErrorModel.class); //parse error and take action callback.onError(ErrorType.UNKNOWN, null, null); } catch (Throwable ex) { callback.onError(ErrorType.UNKNOWN, null, null); } } }); } @Override public void onResponse(Response response) throws IOException { final BaseModel data = gson.fromJson(response.body().charStream(), new TypeToken>() { }.getType()); handler.post(new Runnable() { @Override public void run() { if (!data.error) { uploads.remove(tempId); callback.onSuccess(data.data, false); } else { uploads.get(tempId).status = UPLOAD_ERROR; uploads.get(tempId).progressValue = -1; callback.onDataError(ErrorType.DATA_INPUT, data); } } }); } }); } public List getCurrentUploadsList() { List currentUploads = new ArrayList(); for (Map.Entry entry : uploads.entrySet()) { UserImage image = new UserImage(); image.image = entry.getKey(); image.status = entry.getValue().status; currentUploads.add(image); } return currentUploads; } public boolean isUploading(String image) { return uploads.containsKey(image); } public String getImagePath(String image) { if (uploads.containsKey(image)) { return uploads.get(image).imagePath; } return null; } public String getApiPath(String image) { if (uploads.containsKey(image)) { return uploads.get(image).apiMethod; } return null; } public int getProgress(String image) { if (uploads.containsKey(image)) { return uploads.get(image).progressValue; } return -1; } public void setProgressBar(String image, ProgressBar progressBar) { if (uploads.containsKey(image)) { uploads.get(image).uploadProgressBar = progressBar; } } private void updateProgressBar(String image) { if (uploads.containsKey(image) && uploads.get(image).uploadProgressBar != null) { uploads.get(image).uploadProgressBar.setProgress(getProgress(image)); } } public int getUploadStatus(String image) { if (uploads.containsKey(image)) return uploads.get(image).status; return 0; } public boolean uploadCanceled(String image) { return uploads.containsKey(image) && uploads.get(image).canceled; } public void cancelUpload(String image) { if (uploads.containsKey(image)) { uploads.get(image).canceled = true; client.cancel(image); } } public void retryUpload(String image, ApiCallback callback) { if (uploads.containsKey(image)) { uploadImage(getApiPath(image), getImagePath(image), image, callback); } } private static class UploadData { ProgressBar uploadProgressBar; int progressValue; String imagePath; int status; boolean canceled; String apiMethod; UploadData() { progressValue = -1; } } }