Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/370.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 下载文件时无法更新循环ProgressBar_Java_Android_Download_Retrofit2_Android Progressbar - Fatal编程技术网

Java 下载文件时无法更新循环ProgressBar

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,

我使用了2下载文件。我无法使用进度值更新ProgressBar。我得到了进步值。所以没有问题。当我将进度值设置为未反映在UI中的进度条时

我说的是RecyclerView适配器中的进度条

下面是我的改装电话, 当单击RecyclerView中的项目时,将调用此方法

 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;
        }
    }