Android 多线程断点下载 Okhttp+AsyncTask 封装下载任务

先看一下效果图

     


实现过程并不是很难 下面代码中会有详细的注释

首先添加依赖和权限

    compile 'com.squareup.okhttp3:okhttp:3.4.1'

    
    
    

下载状态的回调接口

public interface DownloadListener {
    void onProgress(int progress);
    void onSuccess();
    void onFailed();
    void onPause();
}

下载的AsyncTask 

public class DownloadTask extends AsyncTask {
    //AsyncTask 的三个泛型 第一个泛型为 doinbackground方法参数类型
    //第二个泛型为 onProgressUpdate的方法参数
    //第三泛型为 doinbackground返回值类型,doinbackground返回值传入onPostExecute方法参数

    public static final int TYPE_SUCCESS = 0;
    public static final int TYPE_FAILED = 1;
    public static final int TYPE_PAUSED = 2;

    private DownloadListener listener;
    private String fieName;
    private String downloadUrl;

    private boolean isPaused = false;

    public DownloadTask(DownloadListener listener) {
        this.listener = listener;
    }

    @Override
    protected Integer doInBackground(String... params) {
        InputStream is = null;
        RandomAccessFile saveFile = null;
        File file = null;

        long downloadLength = 0;
        //下载网址
        downloadUrl = params[0];
        fieName = downloadUrl.substring(downloadUrl.lastIndexOf("/")) + ".apk";
        //相对路径
        String dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
        file = new File(dir + fieName);

        //如果文件存在,那么获取已经下载的文件的长度
        if (file.exists()) {
            downloadLength = file.length();
        }
        //获取文件总长度
        long contentLength = getContentLength(downloadUrl);

        //如果没有获取到网络上文件长度则失败
        if (contentLength == 0){
            return TYPE_FAILED;
        }
        //如果获取到的网络文件长度和本地相同则是已经下载成功
        else if (contentLength == downloadLength) {
            return TYPE_SUCCESS;
        }

        //开始下载

        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                //向服务器添加请求头可以跳过已经下载的地方进行下载
                .addHeader("RANGE","bytes=" +  downloadLength + "-")
                .url(downloadUrl)
                .build();
        try {
            Response response = client.newCall(request).execute();
            if (response != null){
                is = response.body().byteStream();
                //随机读写 rw 读写 如果文件不存在自动创建
                saveFile = new RandomAccessFile(file,"rw");
                //跳过已经下载的长度
                saveFile.seek(downloadLength);
                //循环字节数组
                byte [] bytes = new byte[1024];
                int length = 0;
                int total = 0;
                while ((length = is.read(bytes)) != -1){
                    //正在读取流时暂停
                    if (isPaused){
                        return TYPE_PAUSED;
                    }else {
                        saveFile.write(bytes,0,length);
                        total += length;
                        //计算已经下载的百分比
                        int progress = (int) ((total + downloadLength)*100/contentLength);
                        //传递下载进度
                        publishProgress(progress);
                    }
                }
                response.body().close();
                return TYPE_SUCCESS;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        //如果网络突然中断则会从上一个判断中出来
        return TYPE_FAILED;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        int progress = values[0];
        listener.onProgress(progress);
    }

    @Override
    protected void onPostExecute(Integer integer) {
        switch (integer){
            case TYPE_SUCCESS:
                listener.onSuccess();
                break;
            case TYPE_FAILED:
                listener.onFailed();
                break;
            case TYPE_PAUSED:
                listener.onPause();
                break;
        }
    }


    //访问网络获取文件大小
    public long getContentLength(String downloadUrl) {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(downloadUrl).build();
        try {
            Response response = client.newCall(request).execute();
            if (response != null && response.isSuccessful()) {
                long contentLength = response.body().contentLength();
                return contentLength;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }

    //给外部调用控制下载暂停
    public void pauseDoenload(){
        isPaused = true;
    }

}

Activity的调用以及布局

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button start_btn1;
    private Button pause_btn1;
    private ProgressBar pb1;
    private DownloadTask task1;
    private ProgressBar pb2;
    private Button start_btn2;
    private Button pause_btn2;
    private DownloadTask task2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        start_btn1 = (Button) findViewById(R.id.start_btn1);
        pause_btn1 = (Button) findViewById(R.id.pause_btn1);

        start_btn1.setOnClickListener(this);
        pause_btn1.setOnClickListener(this);
        pb1 = (ProgressBar) findViewById(R.id.pb1);
        pb2 = (ProgressBar) findViewById(R.id.pb2);
        pb2.setOnClickListener(this);
        start_btn2 = (Button) findViewById(R.id.start_btn2);
        start_btn2.setOnClickListener(this);
        pause_btn2 = (Button) findViewById(R.id.pause_btn2);
        pause_btn2.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.start_btn1:
                task1 = new DownloadTask(new DownloadListener() {
                    @Override
                    public void onProgress(int progress) {
                        pb1.setProgress(progress);
                    }

                    @Override
                    public void onSuccess() {
                        Toast.makeText(MainActivity.this, "下载成功", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onFailed() {
                        Toast.makeText(MainActivity.this, "网络异常", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onPause() {
                        Toast.makeText(MainActivity.this, "下载暂停", Toast.LENGTH_SHORT).show();
                    }
                    
                });

                task1.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"http://cdn.xiaoxiongyouhao.com/apps/androilas.apk");
                Toast.makeText(this, "开始下载", Toast.LENGTH_SHORT).show();
                break;
            case R.id.pause_btn1:
                task1.pauseDoenload();
                break;
            case R.id.start_btn2:
                task2 = new DownloadTask(new DownloadListener() {
                    @Override
                    public void onProgress(int progress) {
                        pb2.setProgress(progress);
                    }

                    @Override
                    public void onSuccess() {
                        Toast.makeText(MainActivity.this, "下载成功", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onFailed() {
                        Toast.makeText(MainActivity.this, "网络异常", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onPause() {
                        Toast.makeText(MainActivity.this, "下载暂停", Toast.LENGTH_SHORT).show();
                    }
                    
                });
                task2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"http://gdown.baidu.com/data/wisegame/f73fc503fad6a503/weixin_1180.apk");
                Toast.makeText(this, "开始下载", Toast.LENGTH_SHORT).show();
                break;
            case R.id.pause_btn2:
                task2.pauseDoenload();
                break;
        }
    }


}



    
        
        



你可能感兴趣的:(Android 多线程断点下载 Okhttp+AsyncTask 封装下载任务)