Retrofit 2 RequestBody writeTo() 方法调用了两次
Retrofit 2 RequestBody writeTo() method called twice
Retrofit 2 RequestBody writeTo()方法调用了两次,我使用的代码如下:
ProgressRequestBody requestVideoFile = new ProgressRequestBody(videoFile, new ProgressRequestBody.UploadCallbacks() {
VideoUploadStore store = new VideoUploadStore();
@Override
public void onProgressUpdate(int percentage) {
if (!mIsCancelled) {
Log.i("UploadServiceManager", "Read Percentage : " + percentage);
data.setUploadPercentage(percentage);
store.updateUploadData(data);
}
}
@Override
public void onError() {
if(!mIsCancelled) {
data.setUploadPercentage(0);
store.updateUploadData(data);
}
}
@Override
public void onFinish() {
}
});
MultipartBody.Part multipartVideo = MultipartBody.Part.createFormData("File", videoFile.getName(), requestVideoFile);
下面的解决方案可能对您有所帮助,尽管可能为时已晚。 :p
删除 Api 客户端中不会执行 writeTo() 函数的 HttpLoggingInterceptor
对象 twice.Basically,HttpLoggingInterceptor
首先加载数据缓冲区(用于内部日志记录目的)通过调用 writeTo() 然后再次调用 writeTo() 将数据上传到服务器。
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient.addInterceptor(logging);
将日志级别从 BODY 降低到 HEADERS、BASIC 或 NONE 为我解决了这个问题
我发现了另一种情况,两次调用 writeTo() 方法。
我使用没有 Retrofit 和 HttpLoggingInterceptor 的 OkHttpClient,我有 两次调用 问题。
解决方法:将AndroidStudio升级到3.1.1并在运行项目配置中启用Advanced Profiling后出现该问题。所以禁用高级分析。
将级别从 BODY 降低到 HEADERS 并删除 HttpLoggingInterceptor 对我来说不是解决方案,因为它解释了调用 api 的情况。你可以像这样启动计数器变量,
private int firstTimeCounter = 0;
然后
@Override
public void writeTo(BufferedSink sink) throws IOException {
firstTimeCounter += 1;
.......
.......
if(firstTimeCounter==2){
try {
while (total != file.length()) {
read = source.read(sink.buffer(), SEGMENT_SIZE);
total += read;
Log.e("progress ", total + " %");
sink.flush();
}
} finally {
okhttp3.internal.Util.closeQuietly(source);
}
}
}
如果您使用 writeTo()
来跟踪文件上传进度,则需要区分 writeTo()
的调用者。基本上 writeTo()
可以被链中的任何拦截器调用,例如任何日志记录拦截器,例如 HttpLoggingInterceptor
/OkHttpProfilerInterceptor
/StethoInterceptor
,此方法不提供任何上下文。
最简单的方法(正如其他答案所指出的)是摆脱那些需要访问请求主体的拦截器。但这可能并不总是可行的。
另一种解决方案是利用服务器调用由 CallServerInterceptor
执行的事实,它是链中的最后一个拦截器(根据文档)。您可以在进一步处理之前检查堆栈跟踪。是的,这很丑陋。但这样一来,当其他人出现并添加另一个拦截器时,您不必修改拦截器或为细微错误留出空间。
override fun writeTo(sink: BufferedSink) {
val isCalledByCallServerInterceptor = Thread.currentThread().stackTrace.any { stackTraceElement ->
stackTraceElement.className == CallServerInterceptor::class.java.canonicalName
}
// TODO
}
Retrofit 2 RequestBody writeTo()方法调用了两次,我使用的代码如下:
ProgressRequestBody requestVideoFile = new ProgressRequestBody(videoFile, new ProgressRequestBody.UploadCallbacks() {
VideoUploadStore store = new VideoUploadStore();
@Override
public void onProgressUpdate(int percentage) {
if (!mIsCancelled) {
Log.i("UploadServiceManager", "Read Percentage : " + percentage);
data.setUploadPercentage(percentage);
store.updateUploadData(data);
}
}
@Override
public void onError() {
if(!mIsCancelled) {
data.setUploadPercentage(0);
store.updateUploadData(data);
}
}
@Override
public void onFinish() {
}
});
MultipartBody.Part multipartVideo = MultipartBody.Part.createFormData("File", videoFile.getName(), requestVideoFile);
下面的解决方案可能对您有所帮助,尽管可能为时已晚。 :p
删除 Api 客户端中不会执行 writeTo() 函数的 HttpLoggingInterceptor
对象 twice.Basically,HttpLoggingInterceptor
首先加载数据缓冲区(用于内部日志记录目的)通过调用 writeTo() 然后再次调用 writeTo() 将数据上传到服务器。
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient.addInterceptor(logging);
将日志级别从 BODY 降低到 HEADERS、BASIC 或 NONE 为我解决了这个问题
我发现了另一种情况,两次调用 writeTo() 方法。 我使用没有 Retrofit 和 HttpLoggingInterceptor 的 OkHttpClient,我有 两次调用 问题。
解决方法:将AndroidStudio升级到3.1.1并在运行项目配置中启用Advanced Profiling后出现该问题。所以禁用高级分析。
将级别从 BODY 降低到 HEADERS 并删除 HttpLoggingInterceptor 对我来说不是解决方案,因为它解释了调用 api 的情况。你可以像这样启动计数器变量,
private int firstTimeCounter = 0;
然后
@Override
public void writeTo(BufferedSink sink) throws IOException {
firstTimeCounter += 1;
.......
.......
if(firstTimeCounter==2){
try {
while (total != file.length()) {
read = source.read(sink.buffer(), SEGMENT_SIZE);
total += read;
Log.e("progress ", total + " %");
sink.flush();
}
} finally {
okhttp3.internal.Util.closeQuietly(source);
}
}
}
如果您使用 writeTo()
来跟踪文件上传进度,则需要区分 writeTo()
的调用者。基本上 writeTo()
可以被链中的任何拦截器调用,例如任何日志记录拦截器,例如 HttpLoggingInterceptor
/OkHttpProfilerInterceptor
/StethoInterceptor
,此方法不提供任何上下文。
最简单的方法(正如其他答案所指出的)是摆脱那些需要访问请求主体的拦截器。但这可能并不总是可行的。
另一种解决方案是利用服务器调用由 CallServerInterceptor
执行的事实,它是链中的最后一个拦截器(根据文档)。您可以在进一步处理之前检查堆栈跟踪。是的,这很丑陋。但这样一来,当其他人出现并添加另一个拦截器时,您不必修改拦截器或为细微错误留出空间。
override fun writeTo(sink: BufferedSink) {
val isCalledByCallServerInterceptor = Thread.currentThread().stackTrace.any { stackTraceElement ->
stackTraceElement.className == CallServerInterceptor::class.java.canonicalName
}
// TODO
}