Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save douglarek/43c320592b9acc4c9224db0e3d4cb6b9 to your computer and use it in GitHub Desktop.

Select an option

Save douglarek/43c320592b9acc4c9224db0e3d4cb6b9 to your computer and use it in GitHub Desktop.
Uploading a file with a progress displayed using OkHttp
package com.appsrise.bildkontakte.data;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.internal.Util;
import java.io.File;
import java.io.IOException;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;
public class CountingFileRequestBody extends RequestBody {
private static final int SEGMENT_SIZE = 2048; // okio.Segment.SIZE
private final File file;
private final ProgressListener listener;
private final String contentType;
public CountingFileRequestBody(File file, String contentType, ProgressListener listener) {
this.file = file;
this.contentType = contentType;
this.listener = listener;
}
@Override
public long contentLength() {
return file.length();
}
@Override
public MediaType contentType() {
return MediaType.parse(contentType);
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
Source source = null;
try {
source = Okio.source(file);
long total = 0;
long read;
while ((read = source.read(sink.buffer(), SEGMENT_SIZE)) != -1) {
total += read;
sink.flush();
this.listener.transferred(total);
}
} finally {
Util.closeQuietly(source);
}
}
public interface ProgressListener {
void transferred(long num);
}
}
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 final String ERROR_GRANT = "invalid_grant";
private static UploadsHandler ourInstance;
private Context context;
private volatile HashMap<String, UploadData> uploads;
private List<Pair<String, String>> 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 GsonB();
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<StateModel> 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, 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<StateModel> data = gson.fromJson(response.body().charStream(), new TypeToken<BaseModel<StateModel>>() {
}.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<UserImage> getCurrentUploadsList() {
List<UserImage> currentUploads = new ArrayList<UserImage>();
for (Map.Entry<String, UploadData> 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<StateModel> 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;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment