Java 下载文件时无法更新循环ProgressBar
我使用了2下载文件。我无法使用进度值更新ProgressBar。我得到了进步值。所以没有问题。当我将进度值设置为未反映在UI中的进度条时 我说的是RecyclerView适配器中的进度条 下面是我的改装电话, 当单击RecyclerView中的项目时,将调用此方法Java 下载文件时无法更新循环ProgressBar,java,android,download,retrofit2,android-progressbar,Java,Android,Download,Retrofit2,Android Progressbar,我使用了2下载文件。我无法使用进度值更新ProgressBar。我得到了进步值。所以没有问题。当我将进度值设置为未反映在UI中的进度条时 我说的是RecyclerView适配器中的进度条 下面是我的改装电话, 当单击RecyclerView中的项目时,将调用此方法 private void downloadFileFromServer(String otpapi, String userName, String password, String code, String vmFileName,
private void downloadFileFromServer(String otpapi, String userName, String password, String code, String vmFileName, String filePath, String vmFileSize, int position, CircularProgressBar circularProgress) {
GetDataForApiCall getDataForApiCall= RetrofitInstance.getRetrofit(url,otpapi,context).create(GetDataForApiCall.class);
Call<ResponseBody> downloadVoicemail= getDataForApiCall.downloadVoiceMail(userName,password,code,vmFileName);
this.circularProgressBar=circularProgress;
this.circularProgressBar.setIndeterminate(false);
this.circularProgressBar.setProgress(0);
this.circularProgressBar.setMax(100);
this.circularProgressBar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AndroidLogger.log(5,"onClick","circularProgressBar onClick executed!!");
Toast.makeText(context,"cancel clicked",Toast.LENGTH_LONG).show();
cancelDownload = true;
}
});
downloadVoicemail.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
boolean downloadResult = writeResponseBodyToDisk(response.body(),vmFileSize,filePath);
if(downloadResult) {
Toast.makeText(context, "File downloaded", Toast.LENGTH_SHORT).show();
updateVoiceMailFilePath(position, filePath);
updateViews(position);
}else {
deleteVoiceMailFileFromLocalSystem(filePath);
updateViews(position);
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
}
我还尝试了侦听器更新值,因为在其他线程上完成了改装调用。所以对于更新UI,我使用了监听器,但这并没有帮助
我正在使用Reformation2进行API调用。所以为了在所有活动中更新UI,我使用了接口侦听器。这适用于所有活动。但当我在RecyclerView适配器类中尝试同样的方法时,无法更新进度条。在调用api之前,我将进度条设置为0,最大值设置为100
下面的案例很好用
API调用前的循环进度条设置为零
下载完成后,圆形进度条将变为勾号
下面的代码不起作用
带负载指示的圆形进度条
注意:我只有在使用Reformation2进行API调用时才会遇到这个问题。如果我使用普通的HTTPUrlConnection在Asynctask内进行API调用,则加载过程可以正常进行
我已经通过下面的代码检查了进度更新是否发生在主线程上
if(Looper.myLooper() == Looper.getMainLooper()) {
circularProgressBar.setProgress(progress);
}
如果满足上述条件,则执行上述操作。即使进度条未更新
我也在下面试过
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = new Runnable() {
@Override
public void run() {
AndroidLogger.log(5,TAG,"Running on UI thread");
circularProgressBar.setProgress(progress);
}
};
mainHandler.post(myRunnable);
}
我把这个放在writeResponseBodyToDisk方法中,在while循环中,
但它只被调用了两次,并且进度条没有更新
我对该部分进行了注释,其中进度条加载将更改为记号标记。之后,当我尝试下载时,一旦下载完成,就可以看到100%的下载完成进度条。未反映前进度百分比更新
请任何人帮我解决这个问题
提前感谢。需要在UI线程中进行UI更新。从背景线程(即
AsyncTask
)设置颜色实际上不会更新UI,因为这不会在UI线程中发生。有几种方法可以更新UI中的进度颜色。我建议使用一个带有回调函数的接口,这样您就可以调用该回调函数,从实现它的片段的活动中更新UI。这里有一个澄清
让我们先声明一个接口
public interface UIUpdater {
void updateUI(int progressValue);
}
现在,在要更新UI的活动或片段中实现此接口
public class MainActivity extends Activity implements UIUpdater {
@Override
public void updateUI(int progressValue) {
// Do the UI update here.
circularProgress.setProgress(progressValue); // Or anything else that you want to do.
}
}
您想修改初始化AsyncTask
的构造函数,使UIUpdater
类作为参数传递
public class YourAsyncTask extends AsyncTask<String, Void, String> {
UIUpdater listener;
public YourAsyncTask(UIUpdater listener) {
this.listener = listener;
}
}
现在,从异步任务开始,在发布进度时,调用侦听器函数,以便使用活动/片段的UI线程更新UI
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
try {
listener.updateUI(values[0]);
}
}
希望你能理解。你的问题不是你在使用回收视图,而是你没有正确使用它 在这里,适配器、视图(RecyclerView)甚至视图持有者都不负责确定任何内容
- 我假设您有一个带有进度条的ViewHolder类型
- 我假设您有一个带有相应
实现的DiffUtilCallback
ListAdapter
- 我假设进度是在其他地方处理/报告的(在您的存储库中,通过viewModel或Presenter,通过用例、交互器,甚至是普通viewModel)
- 您的适配器现在无事可做,只能等待
- 更新进度时,您将准备要显示的列表,以便更新进度已更改的项目
- 然后,将此新列表(以及新进度)提交给适配器
- 您的DiffUtil会计算此值(它也可以是异步的!)
- 您的RecyclerView已神奇地更新,无需破解任何东西
这样想一下,想象一下你拥有了所有这些,而你更新的“进度值”中有一个小错误。在ViewModel或UseCase/interactor中搜索将改装值转换为您的
,或在您的意大利面回调代码中搜索所有位置的小功能会更容易些吗?谢谢大家尝试帮助我
这个答案帮助我更新了ProgressBar
在身体课上
public class ProgressResponseBody extends ResponseBody {
private final String TAG=ProgressResponseBody.class.getSimpleName();
private ResponseBody responseBody;
private BufferedSource bufferedSource;
public ProgressResponseBody(ResponseBody responseBody, DownloadVoicemailListener progressListener) {
this.responseBody = responseBody;
progressListener.readFile(responseBody);
}
@Override public MediaType contentType() {
return responseBody.contentType();
}
@Override public long contentLength() {
return responseBody.contentLength();
}
@NotNull
@Override public BufferedSource source() {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
@Override public long read(Buffer sink, long byteCount) throws IOException {
return byteCount;
}
};
}
}
我的recylerview项目中有进度条。。我正在分配回收器适配器内部的进度。这就是为什么在这种情况下我不知道如何使用侦听器的原因。您也可以为适配器使用类似的实现。适配器可以实现
UIUpdater
,并可以覆盖其中的相同方法。如果有帮助的话,您可能需要修改接口,为position获取一个额外的参数,以使用RecyclerView
。感谢您的回答:-)。但无法解决我的pbm。我正在进行2响应内的异步测试。可能这就是问题所在。调用了think so.overrided方法,但未反映在UI中。所以尝试了不同的方法,比如使用handler,runOnUIthread。但是没有什么能帮你谢谢你的回答。在我的例子中,我在一个项目的onclick监听器中进行改造调用。我正在writeResponseBodyToDisk方法中的while循环中更新进度条。但未反映在UI中。您如何告诉适配器数据已更改?感谢您的帮助:-)我找到了解决方案。稍后将在这里发布。不用担心,很高兴知道您找到了解决方案。如果您感兴趣,我修改了一个不相关的示例,以便在“假”慢速操作期间显示进度条。你可以看看
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
try {
listener.updateUI(values[0]);
}
}
public static Retrofit getDownloadRetrofit(String baseUrl, DownloadVoicemailListener listener) {
return new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(getOkHttpDownloadClientBuilder(listener).build())
.build();
}
private static OkHttpClient.Builder getOkHttpDownloadClientBuilder(DownloadVoicemailListener listener) {
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder().connectionSpecs(Collections.singletonList(getConnectionSpec()));
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
if (!releaseMode) {
logging.level(HttpLoggingInterceptor.Level.BODY);
httpClientBuilder.addInterceptor(logging);
}
httpClientBuilder.connectTimeout(20, TimeUnit.SECONDS);
httpClientBuilder.writeTimeout(0, TimeUnit.SECONDS);
httpClientBuilder.readTimeout(5, TimeUnit.MINUTES);
httpClientBuilder.addInterceptor(new Interceptor() {
@NotNull
@Override
public Response intercept(@NotNull Interceptor.Chain chain) throws IOException {
if (listener == null) return chain.proceed(chain.request());
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), listener))
.build();
}
});
return httpClientBuilder;
}
public class ProgressResponseBody extends ResponseBody {
private final String TAG=ProgressResponseBody.class.getSimpleName();
private ResponseBody responseBody;
private BufferedSource bufferedSource;
public ProgressResponseBody(ResponseBody responseBody, DownloadVoicemailListener progressListener) {
this.responseBody = responseBody;
progressListener.readFile(responseBody);
}
@Override public MediaType contentType() {
return responseBody.contentType();
}
@Override public long contentLength() {
return responseBody.contentLength();
}
@NotNull
@Override public BufferedSource source() {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
@Override public long read(Buffer sink, long byteCount) throws IOException {
return byteCount;
}
};
}
}
@Override
public void readFile(ResponseBody responseBody) {
boolean result = writeResponseBodyToDisk(responseBody);
}
private boolean writeResponseBodyToDisk(ResponseBody body) {
try {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
long fileSizeDownloaded = 0;
AndroidLogger.log(5, TAG, "File path" + filePath);
AndroidLogger.log(5, TAG, "File size" + fileSize);
long lengthOfFile = Long.parseLong(String.format("%.0f", Double.parseDouble(this.fileSize))) * 1024;
AndroidLogger.log(5, TAG, "filesize" + fileSize + "length of file" + lengthOfFile);
inputStream = body.byteStream();
outputStream = new FileOutputStream(this.filePath);
byte[] data = new byte[4096];
long total = 0;
int count;
while ((count = inputStream.read(data)) != -1) {
if (cancelDownload) {
AndroidLogger.log(5,TAG,"Cancel download clicked");
inputStream.close();
return false;
}
total += count;
outputStream.write(data, 0, count);
fileSizeDownloaded += count;
if (lengthOfFile > 0) {
AndroidLogger.log(5, TAG, "FileSize downloaded" + fileSizeDownloaded);
int progress = (int) (fileSizeDownloaded * 100 / lengthOfFile);
AndroidLogger.log(5, TAG, "Length of file" + lengthOfFile);
AndroidLogger.log(5, TAG, "Progress" + progress);
((Activity) context).runOnUiThread(new Runnable() {
@Override
public void run() {
circularProgressBar.setProgress(progress);
}
});
}
}
AndroidLogger.log(5, TAG, "file download: " + fileSizeDownloaded + " of " + fileSize);
outputStream.flush();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
}