如何解决Retrofit单文件上传时进度条重复显示的问题?
解决Retrofit上传文件时进度条重复显示的问题
我懂你遇到的糟心问题——传单个文件进度条居然跑了两次全程,这体验确实够别扭的。你猜的方向没错,核心原因是你的ProgressRequestBody里的writeTo方法被调用了两次,大概率是OkHttp的自动重试/重定向机制搞的鬼(比如遇到临时重定向,OkHttp会默默重试一次请求)。
下面是调整后的ProgressRequestBody代码,通过添加状态标记来彻底避免重复的进度回调:
public class ProgressRequestBody extends RequestBody { private File mFile; private UploadCallbacks mListener; private static final int DEFAULT_BUFFER_SIZE = 2048; // 标记是否已经完成过一次完整的上传流程 private boolean mIsUploadCompleted = false; // 记录已回调过的最高进度,避免重复推送相同/更低的进度值 private int mReportedMaxProgress = 0; public interface UploadCallbacks { void onProgressUpdate(int percentage); void onError(); void onFinish(); } public ProgressRequestBody(File file, UploadCallbacks listener) { mFile = file; mListener = listener; } @Override public MediaType contentType() { return MediaType.parse("image/*"); } @Override public long contentLength() throws IOException { return mFile.length(); } @Override public void writeTo(BufferedSink sink) throws IOException { Source source = null; try { source = Okio.source(mFile); long totalWritten = 0; long read; while ((read = source.read(sink.buffer(), DEFAULT_BUFFER_SIZE)) != -1) { totalWritten += read; sink.flush(); int currentPercentage = (int) (100 * totalWritten / mFile.length()); // 只在进度有提升且未完成上传时,才推送进度更新 if (currentPercentage > mReportedMaxProgress && !mIsUploadCompleted) { mListener.onProgressUpdate(currentPercentage); mReportedMaxProgress = currentPercentage; } } // 确保完成回调只触发一次 if (!mIsUploadCompleted) { // 兜底设置进度为100,避免字节计算误差导致进度停在99% mListener.onProgressUpdate(100); mListener.onFinish(); mIsUploadCompleted = true; } } catch (IOException e) { // 错误回调同样只触发一次 if (!mIsUploadCompleted) { mListener.onError(); mIsUploadCompleted = true; } throw e; } finally { Util.closeQuietly(source); } } }
关键优化点:
mIsUploadCompleted标记:确保完成、错误回调只会触发一次,彻底杜绝重复结束提示mReportedMaxProgress变量:避免重复推送相同或更低的进度值,防止进度条出现"回退"或重复跳动- 兜底100%进度:避免因字节计算的微小误差,导致进度条卡在99%无法完成
这样修改后,哪怕writeTo被调用多次,进度条也只会完整走一次从0到100的流程,不会再出现重复显示的问题。
内容的提问来源于stack exchange,提问作者saneesh
相关产品推荐
相关产品推荐

