Android download file with Progressbar okHttp



In android it is often required to download file from server.
I generally use OkHttp and apache common io to download files.

OkHttp : This is the library which I mostly use for my projects.
Apache Common IO : This is the library which I use for file manipulation.

Lets start by adding these library to the build.gradle


    compile group: 'commons-io', name: 'commons-io', version: '2.6'
    compile 'com.facebook.stetho:stetho-okhttp3:1.5.0'





Lets create and util file namely DownloadUtils.java which will be responsible for downloading and showing progress bar.
I just modified the code sample of okHttp for my need



   package skd.app.androidfeatures.utils;


/*
 * Copyright (C) 2015 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import android.app.ProgressDialog;
import android.content.Context;
import android.util.Log;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;

public final class DownloadUtils {

    String fileName;
    String fileUrl;
    Context mContext;

    File root = android.os.Environment.getExternalStorageDirectory();
    File downloadDir = new File(root.getAbsolutePath() + "/androidfeatures/"); //it is my root directory
    ProgressDialog progress;
    final int totalProgressTime = 100;

    /**
     * This method will start downloading the file
     */
    public void startDownload() {
        progress.show();
        Log.wtf("SKDINFO", "Download started");
        //setup the dirs
        final File tmpFile = new File(downloadDir.getAbsolutePath() + "/" + fileName);
        if (downloadDir.exists() == false) {
            downloadDir.mkdirs();
            Log.wtf("SKDINFO", "folder created");
        }

        //setup the request
        final Request request = new Request.Builder()
                .url(fileUrl)
                .build();

        //setup the progressListner
        final ProgressListener progressListener = new ProgressListener() {
            boolean firstUpdate = true;

            @Override
            public void update(long bytesRead, long contentLength, boolean done) {
                if (done) {
                    Log.wtf("SKDINFO", "Download Complete");

                } else {

                    if (firstUpdate) {
                        firstUpdate = false;
                        if (contentLength == -1) {
                            Log.wtf("SKDINFO", "content-length: unknown");
                        } else {
                            Log.wtf("SKDINFO", "content-length: " + contentLength);
                        }
                    }


                    if (contentLength != -1) {
                        Log.wtf("SKDINFO", "" + (100 * bytesRead) / contentLength);
                        progress.setProgress((int)((100 * bytesRead) / contentLength));
                    }
                }
            }
        };


        //init okHttp client
        final OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(60, TimeUnit.MILLISECONDS)
                .readTimeout(60,TimeUnit.SECONDS)
                .addNetworkInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        Response originalResponse = chain.proceed(chain.request());
                        return originalResponse.newBuilder()
                                .body(new ProgressResponseBody(originalResponse.body(), progressListener))
                                .build();
                    }
                })
                .build();

        //send the request and write the file

            Log.wtf("SKDINFO", "Download Starting");

            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Response response = client.newCall(request).execute();

                        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

                        //download Success now
                        Log.wtf("SKDINFO", "Download Completed");
                        FileUtils.copyInputStreamToFile(response.body().byteStream(), tmpFile);
                        response.close(); //close reponse to avoid memory leak
                        progress.dismiss();
                    }catch (IOException e)
                    {
                        e.printStackTrace();
                        progress.dismiss();

                    }

                }
            }).start();





    }

  public DownloadUtils(Context context, String fileUrl, String fileName) {
        this.fileUrl = fileUrl;
        this.fileName = fileName;
        this.mContext = context;
        progress = new ProgressDialog(context);
        progress.setMessage("Downloading form ");
        progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progress.setIndeterminate(false);
        progress.setCancelable(false);

      Log.wtf("SKDINFO", "DownloadUtils" + fileName);

    }

    /**
     * custom response body
     */
    private static class ProgressResponseBody extends ResponseBody {

        private final ResponseBody responseBody;
        private final ProgressListener progressListener;
        private BufferedSource bufferedSource;

        ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) {
            this.responseBody = responseBody;
            this.progressListener = progressListener;
        }

        @Override
        public MediaType contentType() {
            return responseBody.contentType();
        }

        @Override
        public long contentLength() {
            return responseBody.contentLength();
        }

        @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 {
                    long bytesRead = super.read(sink, byteCount);
                    // read() returns the number of bytes read, or -1 if this source is exhausted.
                    totalBytesRead += bytesRead != -1 ? bytesRead : 0;
                    progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
                    return bytesRead;
                }
            };
        }
    }

    /**
     * Listner
     */
    interface ProgressListener {
        void update(long bytesRead, long contentLength, boolean done);
    }


}




Now Lets use this class.
Create and activity with a button in the layout.


public class DownladActivity extends AppCompatActivity {


    Button downloadbtn;
    Context mContext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_downlad);
        mContext = this;

        downloadbtn = (Button) findViewById(R.id.button6);

        Log.wtf("SKDINFO", "download activity");


        downloadbtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Toast.makeText(mContext, "Start", Toast.LENGTH_SHORT).show();
                DownloadUtils down = new DownloadUtils(mContext, "http://mirrors.jenkins.io/war-stable/latest/jenkins.war", "package.zip");
                // DownloadUtils down = new DownloadUtils(mContext,"http://192.168.0.106/test/package.zip","package.zip");
                down.startDownload();


            }
        });


    }
}








Comments