OKHTTP_三行代码实现文件下载(dialog显示进度)

后来写了一篇文件下载的,使用的Xutil框架 ,稳定性更佳,建议大家使用,大型文件不推荐OKHTTp

博客地址 :http://blog.****.net/fkgjdkblxckvbxbgb/article/details/78273687


周末早,接下来几篇博客会对网络请求以及上传下载进行一个最后是总结 。

封装一个下载的工具类,使用OKHTTP实现带进度条下载,dialog弹窗显示进度。目前项目的网络请求框架基本都使用OKhttp,下载,上传 用这个也是好的,看图

本来是做的是电视版本的,用虚拟机测试的,dialog样式有变化 ,可以自己在项目中修改dialog的相关尺寸

不做和断点续传相关的,项目中的下载请求文件较小,没必要 。

项目是5.0的手机测试的,如果有更高的版本,请自行处理读写内存卡相关的权限 。

OKHTTP_三行代码实现文件下载(dialog显示进度)


先看主界面相关的代码,4行搞定 。

项目的类不多 ,思路清晰,结构简单,可以直接拿过来稍微改定就可以在项目中使用。


完整代码下载地址 : http://download.****.net/detail/fkgjdkblxckvbxbgb/9907051


String downUrl = "http://58.63.233.48/app.znds.com/down/20170712/ystjg_2.6.0.1059_dangbei.apk";
String downPath = URL_VIDEO + "/tengxun.apk";
downManager = new DownManager(MainActivity.this);
downManager.downSatrt(downUrl, downPath, "是否下载《腾讯视频》");


使用dawnManager去封装下载util,和dialog的显示以及dialog进度条的更新

package com.reeman.demo.http;


import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.widget.Toast;

import com.reeman.demo.http.dialog.DownDialog;

public class DownManager implements DownListener, DownDialog.DownDialogListener {

    Context context;
    DownDialog downDialog;
    DownUtil downUtil;

    public DownManager(Context context) {
        this.context = context;
        downDialog = new DownDialog(context);
        downDialog.setOnDialogClickListener(this);
        downUtil = new DownUtil(this);
    }

    public static final int DOWN_START = 0;
    public static final int DOWN_PROGRESS = DOWN_START + 1;
    public static final int DOWN_SUCCESS = DOWN_PROGRESS + 1;
    public static final int DOWN_FAILED = DOWN_SUCCESS + 1;


    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case DOWN_START:
                    downDialog.updateView(0, "准备下载", 0);
                    break;
                case DOWN_PROGRESS:
                    int progress = msg.arg1;
                    long speed = (long) msg.obj;
                    downDialog.updateView(progress, "下载中", speed);
                    break;
                case DOWN_SUCCESS:
                    downDialog.updateView(100, "下载完成", 0);
                    downDialog.dissmiss();
                    Toast.makeText(context, "下载完成", Toast.LENGTH_SHORT).show();
                    break;
                case DOWN_FAILED:
                    downDialog.updateView(0, "下载异常", 0);
                    break;
            }
        }
    };

    /***
     * 开始下载
     * @param downUrl
     * 下载地址
     * @param downPath
     * 保存的地址
     * @param desc
     * dialog显示的描述
     */
    String downUrl;
    String downPath;

    public void downSatrt(String downUrl, String downPath, String desc) {
        this.downUrl = downUrl;
        this.downPath = downPath;
        downDialog.show(desc);
    }

    @Override
    public void downStart() {
        handler.sendEmptyMessage(DOWN_START);
    }

    @Override
    public void downProgress(int progress, long speed) {
        Message msg = new Message();
        msg.what = DOWN_PROGRESS;
        msg.arg1 = progress;
        msg.obj = speed;
        handler.sendMessage(msg);
    }

    @Override
    public void downSuccess(String downUrl) {
        handler.sendEmptyMessage(DOWN_SUCCESS);

    }

    @Override
    public void downFailed(String failedDesc) {
        handler.sendEmptyMessage(DOWN_FAILED);
    }

    @Override
    public void noSure() {
        downUtil.cacleDown();
    }

    @Override
    public void sure() {
        downUtil.downFile(downUrl, downPath);
    }
}

下载状态接口

package com.reeman.demo.http;


public interface DownListener {
    /**
     * 开始下载
     */
    void downStart();

    /***
     * 下载进度,和速度
     * @param progress
     * @param speed
     */
    void downProgress(int progress, long speed);

    /***
     * 下载完成
     * @param downUrl
     */
    void downSuccess(String downUrl);

    /***
     * 下载失败
     * @param failedDesc
     */
    void downFailed(String failedDesc);

}

下载的util

package com.reeman.demo.http;

import android.os.Environment;
import android.util.Log;
import android.webkit.DownloadListener;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Dispatcher;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * Created by reeman on 2017/7/21.
 */

public class DownUtil implements Callback {

    OkHttpClient mOkHttpClient;
    DownListener downListener;
    String downPath;
    String downUrl;

    public DownUtil(DownListener downListener) {
        this.downListener = downListener;
        mOkHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .build();
    }


    public void downFile(String downUrl, String downPath) {
        this.downUrl = downUrl;
        this.downPath = downPath;
        try {
            downListener.downStart();
            String downDir = downPath.substring(0, downPath.lastIndexOf("/")).trim();
            String downName = downPath.substring(downPath.lastIndexOf("/") + 1, downPath.length()).trim();
            Log.i("down", "下载地址==" + downDir + "   下载的名字==" + downName);
            File destDir = new File(downDir);
            if (destDir.isDirectory() && !destDir.exists()) {
                destDir.mkdirs();
            }
            Request request = new Request.Builder().url(downUrl).build();
            mOkHttpClient.newCall(request).enqueue(this);
        } catch (Exception e) {
            downListener.downFailed(e.toString());
            Log.d("down", "=================error==" + e.toString());
        }
    }

    public void cacleDown() {
        Dispatcher dispatcher = mOkHttpClient.dispatcher();
//        for (Call call : dispatcher.queuedCalls()) {
//            call.cancel();
//        }
        for (Call call : dispatcher.runningCalls()) {
            call.cancel();
        }
    }


    @Override
    public void onFailure(Call call, IOException e) {
        downListener.downFailed(e.toString());
        Log.d("down", "onFailure");
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        InputStream is = null;
        byte[] buf = new byte[2048];
        int len = 0;
        FileOutputStream fos = null;
        try {
            is = response.body().byteStream();
            long total = response.body().contentLength();
            File file = new File(downPath);
            if (file.exists()) {
                Log.i("down", "文件存在,删除文件==");
                file.delete();
            }
            if (!file.exists() && file.isFile()) {
                Log.i("down", "下载文件不存在创建文件==");
                boolean isCreat = file.createNewFile();
                Log.i("down", "创建文件==" + isCreat);
            }
            fos = new FileOutputStream(file);
            long sum = 0;
            long saveSum = 0;
            while ((len = is.read(buf)) != -1) {
                fos.write(buf, 0, len);
                sum += len;
                final int progress = (int) (sum * 1.0f / total * 100);
                final long speed = sum - saveSum;
                saveSum = sum;
                Log.d("down", "===================" + progress + "  speed =" + speed);
                updateProgress(progress, speed);
            }
            fos.flush();
            downListener.downSuccess(downPath);
            Log.d("down", "=================success==");
        } catch (Exception e) {
            downListener.downFailed(e.toString());
            Log.d("down", "=================error==" + e.toString());
        } finally {
            if (is != null)
                is.close();
            if (fos != null)
                fos.close();
        }
    }

    int lastProgress = 0;

    private void updateProgress(int progress, long speed) {
        if (progress > lastProgress) {
            downListener.downProgress(progress, speed);
        }
        lastProgress = progress;
    }


}

下载的显示dialog ,里面有一个自定义的蓝色的进度条,可以直接替换android 自带的progressBar,完整代码,在文章顶部

package com.reeman.demo.http.dialog;


import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.Window;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;

import com.reeman.demo.R;
import com.reeman.demo.http.view.RopeProgressBar;

public class DownDialog {
    private Dialog dialog;
    DownDialogListener dialogClick;
    public RopeProgressBar view_progress;
    public TextView tv_title;
    public TextView tv_speed;
    Context context;
    private TextView tv_desc_update;

    /***
     * 刷新dialog
     *
     * @param progress
     *            进度
     * @param desc
     *            下载秒速
     * @param speed
     *            下载速度
     */
    public void updateView(int progress, String desc, long speed) {
        view_progress.setProgress(progress);
        tv_title.setTextColor(0xff1fbaf3);
        tv_title.setText("文件下载(" + desc + ")");
        tv_speed.setText(speed + " kb/s");
        if (desc.contains("异常")) {
            tv_title.setTextColor(Color.RED);
            tv_title.setText("下载异常,请重新启动程序");
        }
    }

    public DownDialog(final Context context) {
        this.context = context;
        if (dialog == null) {
            dialog = new Dialog(context, R.style.MyDialog);
        }
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        int width = 800;
        int height = 1280;
        LayoutParams params = new RelativeLayout.LayoutParams(width, height);
        View dialog_view = View.inflate(context, R.layout.dialog_down, null);
        dialog.setContentView(dialog_view, params);

        dialog.setCancelable(false); // true点击屏幕以外关闭dialog
        tv_title = (TextView) dialog_view.findViewById(R.id.dialog_title);
        tv_desc_update = (TextView) dialog_view.findViewById(R.id.tv_desc_update);
        tv_speed = (TextView) dialog_view.findViewById(R.id.tv_speed);
        btn_no = (Button) dialog_view.findViewById(R.id.btn_dialog_no);
        btn_dialog_yes = (Button) dialog_view.findViewById(R.id.btn_dialog_yes);

        view_progress = (RopeProgressBar) dialog_view.findViewById(R.id.update_progress);
        btn_dialog_yes.setOnClickListener(new OnClickListener() {
            @SuppressLint("ResourceAsColor")
            public void onClick(View v) {
                view_progress.setVisibility(View.VISIBLE);
                tv_desc_update.setVisibility(View.INVISIBLE);
                btn_dialog_yes.setVisibility(View.GONE);
                dialogClick.sure();
            }
        });

        btn_no.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if (dialogClick != null) {
                    dialogClick.noSure();
                    dissmiss();
                }
            }
        });

        btn_no.setBackgroundColor(0xffB3B3B3);
        btn_dialog_yes.setBackgroundColor(0xffB3B3B3);
        btn_no.setOnFocusChangeListener(onFocusChangeListener);
        btn_dialog_yes.setOnFocusChangeListener(onFocusChangeListener);
    }

    private OnFocusChangeListener onFocusChangeListener = new OnFocusChangeListener() {

        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (hasFocus) {
                v.setBackgroundColor(Color.BLUE);
            } else {
                v.setBackgroundColor(0xffB3B3B3);
            }
        }
    };


    Button btn_no;
    final Button btn_dialog_yes;

    public void show(String desc) {
        view_progress.setVisibility(View.INVISIBLE);
        tv_desc_update.setVisibility(View.VISIBLE);
        if (desc != null && desc.length() > 4) {
            tv_desc_update.setText(desc);
        }
        tv_speed.setText("0kb/s");
        dialog.show();
    }

    public void dissmiss() {
        if (dialog == null) {
            return;
        }
        btn_dialog_yes.setVisibility(View.VISIBLE);
        if (dialog.isShowing()) {
            dialog.dismiss();
        }
    }

    public void setOnDialogClickListener(DownDialogListener dc) {
        dialogClick = dc;
    }

    public interface DownDialogListener {
        void noSure();

        void sure();
    }

}