Search code examples
javaandroiddownloadretrofit2android-progressbar

Unable to update Circular ProgressBar while downloading file


I have used Retrofit2 for file download. I am not able to update ProgressBar with progress value. I got progress value. So there is not issue. When I set the progress value to progress bar not reflected in UI.

I am talking about Progress Bar which is present inside RecyclerView Adapter.

Below is my retrofit call, And this method will be called when clicking a item inside 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,TAG,"-1 value so break");
                        break;
                    }
                    outputStream.write(fileReader, 0, read);

                    fileSizeDownloaded += read;
                    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);
                    this.circularProgressBar.setProgress(progress);
                        update(progress);
                    }
                    AndroidLogger.log(5,TAG, "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;
        }
    }

Also I have tried Listener to update value because retrofit call done on some other thread. So for update UI I have used listener which is not helped.

I am using Retrofit2 for making API calls. So for updating UI in all Activities I had used interface listeners. This works perfect for all Activities. But when I tried the same thing in RecyclerView Adapter class, not able to update progress bar. Before calling api I had set Progress bar to 0 and max to 100.

Below case Works fine,

Circular ProgressBar before API call set to Zero

Circular ProgressBar after download Completed will change to a tick mark

Below is not Working,

Circular ProgressBar with indication of loading

NOTE: I am facing this issue only when used Retrofit2 to make API call. If I used normal HTTPUrlConnection for making API call inside a Asynctask, then progress loading working fine.

I have checked whether the progress updation is occurs on main thread or not by below code,

if(Looper.myLooper() == Looper.getMainLooper()) {
circularProgressBar.setProgress(progress);
}

The above if condition is satisfied. Eventhough Progress bar not updated.

Also I have tried below,

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


                    }

I have placed this inside writeResponseBodyToDisk method, inside while loop, But it was called only two times and progress bar not updated.

I commented the part, where the progress bar loading will change to a tick mark. After that when I tried download,once download completed able to see 100 percent download completed in progress bar. Before progress percent updation not reflected.

Please Anybody help me out to solve this issue.

Thanks in advance.


Solution

  • Thank you all for trying to help me!!

    This answer helped me to update Circular ProgressBar https://stackoverflow.com/a/42119419/11630822

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

    In Progressbody class,

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