下载文件

问题描述

我已使用Retrofit2进行文件下载。我无法使用进度值更新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) {

            }
        });
    }

private boolean writeResponseBodyTodisk( ResponseBody body,String fileSize,String filePath) {
        try {
            InputStream inputStream = null;
            OutputStream outputStream = null;

            try {
                byte[] fileReader = new byte[8192];
                //long fileSize = body.contentLength();
                long fileSizeDownloaded = 0;
                long lengthOfFile = Long.parseLong( String.format( "%.0f",Double.parseDouble(fileSize )) )  * 1024;
                AndroidLogger.log(5,TAG,"filesize"+fileSize + "length of file"+lengthOfFile);
                inputStream = body.byteStream();
                outputStream = new FileOutputStream(filePath);

                while (true) {
                    int read = inputStream.read(fileReader);

                    if(cancelDownload){
                        inputStream.close();
                        return false;
                    }
                    if (read == -1) {
                        AndroidLogger.log(5,"-1 value so break");
                        break;
                    }
                    outputStream.write(fileReader,read);

                    fileSizeDownloaded += read;
                    if(lengthOfFile >0) {
                    AndroidLogger.log(5,"FileSize downloaded"+ fileSizeDownloaded);
                        int progress = (int) (fileSizeDownloaded * 100 / lengthOfFile);
                    AndroidLogger.log(5,"Length of  file"+ lengthOfFile);
                    AndroidLogger.log(5,"Progress"+ progress);
                    this.circularProgressBar.setProgress(progress);
                        update(progress);
                    }
                    AndroidLogger.log(5,"file download: " + fileSizeDownloaded + " of " + fileSize);
                }

                outputStream.flush();

                return true;
            } catch (IOException e) {
                return false;
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }

                if (outputStream != null) {
                    outputStream.close();
                }
            }
        } catch (IOException e) {
            return false;
        }
    }

我还尝试了Listener更新值,因为在其他线程上进行了改造调用。因此,对于更新UI,我使用了没有帮助的监听器。

我正在使用Retrofit2进行API调用。因此,为了在所有活动中更新UI,我使用了接口侦听器。这非常适合所有活动。但是,当我在RecyclerView Adapter类中尝试相同的操作时,无法更新进度栏。在调用api之前,我已将进度栏设置为0,最大设置为100。

以下情况可以正常工作

API调用之前的循环ProgressBar设置为零

下载完成后的圆形ProgressBar将变为刻度线

以下内容不起作用

带有加载指示的圆形ProgressBar

注意:仅当使用Retrofit2进行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,"Running on UI thread");
                                circularProgressBar.setProgress(progress);
                            } 
                        };
                        mainHandler.post(myRunnable);


                    }

我将其放置在while循环内的writeResponseBodyTodisk方法内, 但这只被调用了两次,进度条没有更新。

评论了该部分,进度条加载将变为刻度线。之后,当我尝试下载时,一旦下载完成就可以看到进度条中的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;
    }
}

因此您可以使用以下方法从活动/片段中调用AsyncTask

YourAsyncTask myTask = new YourAsyncTask(this); // When you are passing this from activity,you are implicitly passing the interface that it implemented. 
myTask.execute(); 

现在,从异步任务开始,在发布进度时,调用侦听器功能,以便使用活动/片段的UI线程更新UI。

protected void onProgressUpdate(Integer... values) {
    super.onProgressUpdate(values);

    try {
       listener.updateUI(values[0]);
    }
} 

希望您能明白。

,

您的问题不是您使用的是RecyclerView,而是您使用的不是正确的问题。

既不是适配器,也不是视图(RecyclerView),甚至也不是ViewHolder的责任来确定此处的任何内容。

  • 我假设您有一个带有进度条的ViewHolder类型。
  • 我假设您有一个ListAdapter<T,K>和相应的DiffUtilCallback实现。
  • 我认为进度是在其他地方处理/报告的(在您的存储库中,通过viewModel或Presenter,通过useCase,Interactor甚至是普通的ViewModel)。
  • 您的适配器现在只需要等待即可。
  • 更新进度时,请准备要显示的列表,以便更新进度已更改的项目。
  • 之后,您将此新列表(具有新进度)提交给适配器。
  • 您的DiffUtil进行计算(也可以是异步的!)
  • 您的RecyclerView进行了神奇的更新,无需破解任何东西。

如果其中任何一个都不正确,请进行必要的调整,以便可以正确测试您的代码,并更好地区分每段代码的关注点。

以这种方式进行思考,假设您拥有所有这些,并且您更新的“进度值”中存在一个小错误。在ViewModel或UseCase / interactor中的小功能中搜索将Retrofit值转换为<Thing>或在意粉回调代码中的所有位置,这会更容易些?

,

谢谢大家为我提供帮助!

此答案帮助我更新了Circular ProgressBar https://stackoverflow.com/a/42119419/11630822

import math
z = []
for i in range(n):
    x = float(input())
    z.append(math.sqrt(x))

for i in z:
  print(i)

Progressbody类,

2.0
1.0
1.4142135623730951
1.7320508075688772
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;
            }
        };
    }


}


相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...