Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Uploading a file with a progress displayed using OkHttp
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 MyPicturesAdapter extends BaseAdapter {
private static final int ITEM_TYPE_ONLINE = 0;
private static final int ITEM_TYPE_DISK = 1;
private List<UserImage> userImages;
private Context context;
private OnActionListener onActionListener;
private LayoutInflater inflater;
public MyPicturesAdapter(Context context) {
super();
this.context = context;
this.userImages = new ArrayList<UserImage>();
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return userImages.size();
}
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getItemViewType(int position) {
return getItem(position).status >= 0 ? ITEM_TYPE_ONLINE : ITEM_TYPE_DISK;
}
@Override
public UserImage getItem(int position) {
return userImages.get(position);
}
@Override
public long getItemId(int position) {
return userImages.get(position).image.hashCode();
}
public void clear() {
this.userImages.clear();
}
public void addAll(Collection<UserImage> images) {
if (images != null) {
this.userImages.addAll(images);
}
}
public void remove(UserImage userImage) {
this.userImages.remove(userImage);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView != null) {
holder = (ViewHolder) convertView.getTag();
} else {
int itemType = getItemViewType(position);
if (itemType == ITEM_TYPE_ONLINE)
convertView = inflater.inflate(R.layout.item_my_pictures_image, parent, false);
else
convertView = inflater.inflate(R.layout.item_my_pictures_upload, parent, false);
holder = new ViewHolder(convertView);
if (itemType == ITEM_TYPE_DISK) {
holder.cancelButtonListener = new CancelButtonListener();
holder.statusIcon.setOnClickListener(holder.cancelButtonListener);
}
convertView.setTag(holder);
}
final UserImage userImage = getItem(position);
if (getItemViewType(position) == ITEM_TYPE_DISK) {
Picasso.with(holder.avatar.getContext())
.load(Uri.fromFile(new File(UploadsHandler.getInstance().getImagePath(userImage.image))))
.noFade()
.fit()
.into(holder.avatar);
userImage.status = UploadsHandler.getInstance().getUploadStatus(userImage.image);
holder.cancelButtonListener.updatePosition(position);
switch (userImage.status) {
case UploadsHandler.UPLOAD_LOADING:
holder.uploadProgress.setVisibility(View.VISIBLE);
UploadsHandler.getInstance().setProgressBar(userImage.image, holder.uploadProgress);
holder.statusText.setVisibility(View.GONE);
holder.statusIcon.setImageResource(R.drawable.icon_mb_cancelupload);
break;
case UploadsHandler.UPLOAD_ERROR:
holder.uploadProgress.setVisibility(View.GONE);
holder.statusText.setVisibility(View.VISIBLE);
holder.statusText.setText(R.string.picture_upload_error);
holder.statusIcon.setImageResource(R.drawable.icon_mb_errorupload);
break;
case UploadsHandler.UPLOAD_ABORTED:
holder.uploadProgress.setVisibility(View.GONE);
holder.statusText.setVisibility(View.VISIBLE);
holder.statusText.setText(R.string.picture_upload_aborted);
holder.statusIcon.setImageResource(R.drawable.icon_mb_refreshupload);
break;
}
holder.statusIndicator.setBackgroundColor(Color.TRANSPARENT);
holder.uploadProgress.setProgress(UploadsHandler.getInstance().getProgress(userImage.image));
} else {
switch (userImage.status) {
case 0:
holder.statusIndicator.setBackgroundColor(context.getResources().getColor(R.color.my_pictures_check_divider));
holder.statusIcon.setImageResource(R.drawable.icon_mb_check);
holder.actionIcon.setImageResource(R.drawable.icon_mb_settings);
break;
// etc
}
holder.statusText.setText(userImage.description);
UIUtils.loadImage(context, holder.avatar, userImage.image);
}
return convertView;
}
public void add(UserImage image) {
this.userImages.add(image);
}
public void setOnActionListener(OnActionListener onActionListener) {
this.onActionListener = onActionListener;
}
static class ViewHolder {
@InjectView(R.id.user_image_avatar)
ImageView avatar;
@InjectView(R.id.user_image_status_indicator)
View statusIndicator;
@InjectView(R.id.user_image_status_icon)
ImageView statusIcon;
@InjectView(R.id.user_image_status_text)
TextView statusText;
@Optional @InjectView(R.id.user_image_upload_progress)
ProgressBar uploadProgress;
@Optional @InjectView(R.id.user_image_action)
ImageView actionIcon;
CancelButtonListener cancelButtonListener;
public ViewHolder(View view) {
ButterKnife.inject(this, view);
}
}
public interface OnActionListener {
public void onAction(int position);
}
private class CancelButtonListener implements View.OnClickListener {
private int position;
private void updatePosition(int pos){
position = pos;
}
@Override
public void onClick(View v) {
if (onActionListener != null)
onActionListener.onAction(position);
}
}
}
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<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 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<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, "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<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;
}
}
}
@krithoonsuwan
Copy link

krithoonsuwan commented Jul 9, 2015

I don't know why my progress is super fast. my file is about 1Mb but took like 30ms to finish progress. It's like progress is the progress of writing buffer not actual uploading to server?

@YounMario
Copy link

YounMario commented Aug 13, 2015

Not good solution in lower version of java environment such as jdk6.0

@priyochatterjee08
Copy link

priyochatterjee08 commented Jan 1, 2016

where is the UserImage class?

@start141
Copy link

start141 commented Mar 15, 2016

@durunvo I have the same problem! If you know how to fix this?

@eduardb
Copy link
Author

eduardb commented Mar 17, 2016

UserImage is just a model class. It can be anything, depending on your needs.

@Winghin2517
Copy link

Winghin2517 commented Apr 18, 2016

Guys, does anyone have a working copy of this gist? I'm prepared to compile one and then share it here but if someone has a working copy and would like to share, it would save me a lot of time. thanks!

@mohdmurtuzakhan
Copy link

mohdmurtuzakhan commented Feb 8, 2017

For this
UIUtils.loadImage(context, holder.avatar, userImage.image);
where can i get UIUtils class and ButterKnife for ButterKnife.inject(this, view);

@nb312
Copy link

nb312 commented May 3, 2018

How wonderful you are!

@aderinto05
Copy link

aderinto05 commented Mar 1, 2019

can share import library for these? this repo didn't put library package.

@smathur12
Copy link

smathur12 commented Apr 25, 2019

does anyone have working directory or project

@pradyotprksh
Copy link

pradyotprksh commented Jun 7, 2022

Thanks for the help. Is there any way to do it with input streams rather than files?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment