下载文件

如何解决下载文件

我已使用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;
            }
        };
    }


}


版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-