Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@Joisar
Forked from eduardb/CountingFileRequestBody.java
Last active August 29, 2015 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Joisar/8e4ad198799cc323ef07 to your computer and use it in GitHub Desktop.
Save Joisar/8e4ad198799cc323ef07 to your computer and use it in GitHub Desktop.
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;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment