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

先看一下效果图

     


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

首先添加依赖和权限

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

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

下载状态的回调接口

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

下载的AsyncTask 

public class DownloadTask extends AsyncTask<String, Integer, Integer> {
    //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;
        }
    }


}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.dllo.download.MainActivity">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ProgressBar
            android:id="@+id/pb1"
            style="@style/Widget.AppCompat.ProgressBar.Horizontal"
            android:layout_weight="2"
            android:layout_width="0dp"
            android:layout_height="match_parent" />
        <Button
            android:id="@+id/start_btn1"
            android:text="开始"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content" />
        <Button
            android:id="@+id/pause_btn1"
            android:text="暂停"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ProgressBar
            android:id="@+id/pb2"
            style="@style/Widget.AppCompat.ProgressBar.Horizontal"
            android:layout_weight="2"
            android:layout_width="0dp"
            android:layout_height="match_parent" />
        <Button
            android:id="@+id/start_btn2"
            android:text="开始"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content" />
        <Button
            android:id="@+id/pause_btn2"
            android:text="暂停"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content" />
    </LinearLayout>



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值