断点下载续传—支持断点续传 ,后台有服务来下载文件。

来源:互联网 发布:js赋值给input 编辑:程序博客网 时间:2024/06/05 20:40

这里写图片描述

分析思路:

开发下载文件的要求有两点:1.支持断点续传 2.后台有服务来下载文件。

1、复制xutils.jar到项目中 libs 点击下载
2、复制 核心类 到你的app文件下
DownloadInfo支持记录保存 。核心类下载
DownloadService有服务支持好处是所有activity关闭,下载不被中断。
DownloadManager作用。用来支持常见的下载操作。
配置服务。调用DownloadManager编写业务逻辑 下载 暂停 续传

核心类展示

DownloadInfo

public class DownloadInfo {    public DownloadInfo() {    }    private long id;    //一个应用只有一个appId 可以根据appId进行存储断点.方便下次查找断点    private String appId;    public String getAppId() {        return appId;    }    public void setAppId(String appId) {        this.appId = appId;    }    @Transient    private HttpHandler<File> handler;    private HttpHandler.State state;    private String downloadUrl;    private String fileName;    private String fileSavePath;    private long progress;    private long fileLength;    private boolean autoResume;    private boolean autoRename;    public long getId() {        return id;    }    public void setId(long id) {        this.id = id;    }    public HttpHandler<File> getHandler() {        return handler;    }    public void setHandler(HttpHandler<File> handler) {        this.handler = handler;    }    public HttpHandler.State getState() {        return state;    }    public void setState(HttpHandler.State state) {        this.state = state;    }    public String getDownloadUrl() {        return downloadUrl;    }    public void setDownloadUrl(String downloadUrl) {        this.downloadUrl = downloadUrl;    }    public String getFileName() {        return fileName;    }    public void setFileName(String fileName) {        this.fileName = fileName;    }    public String getFileSavePath() {        return fileSavePath;    }    public void setFileSavePath(String fileSavePath) {        this.fileSavePath = fileSavePath;    }    public long getProgress() {        return progress;    }    public void setProgress(long progress) {        this.progress = progress;    }    public long getFileLength() {        return fileLength;    }    public void setFileLength(long fileLength) {        this.fileLength = fileLength;    }    public boolean isAutoResume() {        return autoResume;    }    public void setAutoResume(boolean autoResume) {        this.autoResume = autoResume;    }    public boolean isAutoRename() {        return autoRename;    }    public void setAutoRename(boolean autoRename) {        this.autoRename = autoRename;    }    @Override    public boolean equals(Object o) {        if (this == o) return true;        if (!(o instanceof DownloadInfo)) return false;        DownloadInfo that = (DownloadInfo) o;        if (id != that.id) return false;        return true;    }    @Override    public int hashCode() {        return (int) (id ^ (id >>> 32));    }}

DownloadService

public class DownloadService extends Service {    private static DownloadManager DOWNLOAD_MANAGER;    public static DownloadManager getDownloadManager(Context appContext) {        if (!DownloadService.isServiceRunning(appContext)) {            Intent downloadSvr = new Intent(appContext,DownloadService.class);            appContext.startService(downloadSvr);        }        if (DownloadService.DOWNLOAD_MANAGER == null) {            DownloadService.DOWNLOAD_MANAGER = new DownloadManager(appContext);        }        return DOWNLOAD_MANAGER;    }    public DownloadService() {        super();    }    @Override    public IBinder onBind(Intent intent) {        return null;    }    @Override    public void onCreate() {        super.onCreate();    }    @Override    public void onStart(Intent intent, int startId) {        super.onStart(intent, startId);    }    @Override    public void onDestroy() {        if (DOWNLOAD_MANAGER != null) {            try {                DOWNLOAD_MANAGER.stopAllDownload();                DOWNLOAD_MANAGER.backupDownloadInfoList();            } catch (DbException e) {                LogUtils.e(e.getMessage(), e);            }        }        super.onDestroy();    }    public static boolean isServiceRunning(Context context) {        boolean isRunning = false;        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);        List<ActivityManager.RunningServiceInfo> serviceList = activityManager.getRunningServices(Integer.MAX_VALUE);        if (serviceList == null || serviceList.size() == 0) {            return false;        }        for (int i = 0; i < serviceList.size(); i++) {            if (serviceList.get(i).service.getClassName().equals(DownloadService.class.getName())) {                isRunning = true;                break;            }        }        return isRunning;    }}

DownloadManager

public class DownloadManager {    private List<DownloadInfo> downloadInfoList;    private int maxDownloadThread = 3;    private Context mContext;    private DbUtils db;    /* package */ DownloadManager(Context appContext) {        ColumnConverterFactory.registerColumnConverter(HttpHandler.State.class, new HttpHandlerStateConverter());        mContext = appContext;        db = DbUtils.create(mContext);// xUtils.db        try {            downloadInfoList = db.findAll(Selector.from(DownloadInfo.class));        } catch (DbException e) {            LogUtils.e(e.getMessage(), e);        }        if (downloadInfoList == null) {            downloadInfoList = new ArrayList<DownloadInfo>();        }    }    public int getDownloadInfoListCount() {        return downloadInfoList.size();    }    public DownloadInfo getDownloadInfo(int index) {        return downloadInfoList.get(index);    }    /***     * 方法 按照应用appId查找断点记录     *      * @param appId     * @return     */    public DownloadInfo getDownloadInfoByAppId(String appId) {        for (DownloadInfo item : downloadInfoList) {            if (TextUtils.equals(item.getAppId(), appId)) {                return item;// 返回指定appId的断点记录            }        }        return null;    }    public void addNewDownload(String appId, String url, String fileName, String target, boolean autoResume, boolean autoRename, final RequestCallBack<File> callback) throws DbException {        final DownloadInfo downloadInfo = new DownloadInfo();        downloadInfo.setAppId(appId);        downloadInfo.setDownloadUrl(url);        downloadInfo.setAutoRename(autoRename);        downloadInfo.setAutoResume(autoResume);        downloadInfo.setFileName(fileName);        downloadInfo.setFileSavePath(target);        HttpUtils http = new HttpUtils();        http.configRequestThreadPoolSize(maxDownloadThread);        HttpHandler<File> handler = http.download(url, target, autoResume, autoRename, new ManagerCallBack(downloadInfo, callback));        downloadInfo.setHandler(handler);        downloadInfo.setState(handler.getState());        downloadInfoList.add(downloadInfo);        db.saveBindingId(downloadInfo);    }    public void resumeDownload(int index, final RequestCallBack<File> callback) throws DbException {        final DownloadInfo downloadInfo = downloadInfoList.get(index);        resumeDownload(downloadInfo, callback);    }    public void resumeDownload(DownloadInfo downloadInfo, final RequestCallBack<File> callback) throws DbException {        HttpUtils http = new HttpUtils();        http.configRequestThreadPoolSize(maxDownloadThread);        HttpHandler<File> handler = http.download(downloadInfo.getDownloadUrl(), downloadInfo.getFileSavePath(), downloadInfo.isAutoResume(), downloadInfo.isAutoRename(), new ManagerCallBack(downloadInfo, callback));        downloadInfo.setHandler(handler);        downloadInfo.setState(handler.getState());        db.saveOrUpdate(downloadInfo);    }    public void removeDownload(int index) throws DbException {        DownloadInfo downloadInfo = downloadInfoList.get(index);        removeDownload(downloadInfo);    }    public void removeDownload(DownloadInfo downloadInfo) throws DbException {        HttpHandler<File> handler = downloadInfo.getHandler();        if (handler != null && !handler.isCancelled()) {            handler.cancel();        }        // 从下载的断点记录集合中移除断点记录(内存)        downloadInfoList.remove(downloadInfo);        // 从数据库删除。        db.delete(downloadInfo);        // 下载一半的文件?100M 55M        String fileSavePath = downloadInfo.getFileSavePath();        // 如果存在下载一半的文件,由于下次找不到断点记录,没法续传,直接删除这个文件节省sd空间.        File file = new File(fileSavePath);        if (file.exists()) {            file.delete();        }    }    public void stopDownload(int index) throws DbException {        DownloadInfo downloadInfo = downloadInfoList.get(index);        stopDownload(downloadInfo);    }    public void stopDownload(DownloadInfo downloadInfo) throws DbException {        HttpHandler<File> handler = downloadInfo.getHandler();        if (handler != null && !handler.isCancelled()) {            handler.cancel();        } else {            downloadInfo.setState(HttpHandler.State.CANCELLED);        }        db.saveOrUpdate(downloadInfo);    }    public void stopAllDownload() throws DbException {        for (DownloadInfo downloadInfo : downloadInfoList) {            HttpHandler<File> handler = downloadInfo.getHandler();            if (handler != null && !handler.isCancelled()) {                handler.cancel();            } else {                downloadInfo.setState(HttpHandler.State.CANCELLED);            }        }        db.saveOrUpdateAll(downloadInfoList);    }    public void backupDownloadInfoList() throws DbException {        for (DownloadInfo downloadInfo : downloadInfoList) {            HttpHandler<File> handler = downloadInfo.getHandler();            if (handler != null) {                downloadInfo.setState(handler.getState());            }        }        db.saveOrUpdateAll(downloadInfoList);    }    public int getMaxDownloadThread() {        return maxDownloadThread;    }    public void setMaxDownloadThread(int maxDownloadThread) {        this.maxDownloadThread = maxDownloadThread;    }    public class ManagerCallBack extends RequestCallBack<File> {        private DownloadInfo downloadInfo;        private RequestCallBack<File> baseCallBack;        public RequestCallBack<File> getBaseCallBack() {            return baseCallBack;        }        public void setBaseCallBack(RequestCallBack<File> baseCallBack) {            this.baseCallBack = baseCallBack;        }        private ManagerCallBack(DownloadInfo downloadInfo, RequestCallBack<File> baseCallBack) {            this.baseCallBack = baseCallBack;            this.downloadInfo = downloadInfo;        }        @Override        public Object getUserTag() {            if (baseCallBack == null)                return null;            return baseCallBack.getUserTag();        }        @Override        public void setUserTag(Object userTag) {            if (baseCallBack == null)                return;            baseCallBack.setUserTag(userTag);        }        @Override        public void onStart() {            HttpHandler<File> handler = downloadInfo.getHandler();            if (handler != null) {                downloadInfo.setState(handler.getState());            }            try {                db.saveOrUpdate(downloadInfo);            } catch (DbException e) {                LogUtils.e(e.getMessage(), e);            }            if (baseCallBack != null) {                baseCallBack.onStart();            }        }        @Override        public void onCancelled() {            HttpHandler<File> handler = downloadInfo.getHandler();            if (handler != null) {                downloadInfo.setState(handler.getState());            }            try {                db.saveOrUpdate(downloadInfo);            } catch (DbException e) {                LogUtils.e(e.getMessage(), e);            }            if (baseCallBack != null) {                baseCallBack.onCancelled();            }        }        @Override        public void onLoading(long total, long current, boolean isUploading) {            HttpHandler<File> handler = downloadInfo.getHandler();            if (handler != null) {                downloadInfo.setState(handler.getState());            }            downloadInfo.setFileLength(total);            downloadInfo.setProgress(current);            try {                db.saveOrUpdate(downloadInfo);            } catch (DbException e) {                LogUtils.e(e.getMessage(), e);            }            if (baseCallBack != null) {                baseCallBack.onLoading(total, current, isUploading);            }        }        @Override        public void onSuccess(ResponseInfo<File> responseInfo) {            HttpHandler<File> handler = downloadInfo.getHandler();            if (handler != null) {                downloadInfo.setState(handler.getState());            }            try {                db.saveOrUpdate(downloadInfo);            } catch (DbException e) {                LogUtils.e(e.getMessage(), e);            }            if (baseCallBack != null) {                baseCallBack.onSuccess(responseInfo);            }        }        @Override        public void onFailure(HttpException error, String msg) {            HttpHandler<File> handler = downloadInfo.getHandler();            if (handler != null) {                downloadInfo.setState(handler.getState());            }            try {                db.saveOrUpdate(downloadInfo);            } catch (DbException e) {                LogUtils.e(e.getMessage(), e);            }            if (baseCallBack != null) {                baseCallBack.onFailure(error, msg);            }        }    }    private class HttpHandlerStateConverter implements ColumnConverter<HttpHandler.State> {        @Override        public HttpHandler.State getFieldValue(Cursor cursor, int index) {            return HttpHandler.State.valueOf(cursor.getInt(index));        }        @Override        public HttpHandler.State getFieldValue(String fieldStringValue) {            if (fieldStringValue == null)                return null;            return HttpHandler.State.valueOf(fieldStringValue);        }        @Override        public Object fieldValue2ColumnValue(HttpHandler.State fieldValue) {            return fieldValue.value();        }        @Override        public ColumnDbType getColumnDbType() {            return ColumnDbType.INTEGER;        }    }}

代码使用实现:

 //获取DownloadManager对象 DownloadManager  mg = DownloadService.getDownloadManager(MyApp.getContext());        //按钮BtnDownload的点击事件        BtnDownload.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {               try {               //查询指定应用下载记录(断点 progress)             DownloadInfo downloadInfo = mg.getDownloadInfoByAppId(data.id + "");                   //判断是否有下载记录,有就是续传 没有就是开始下载                   if (downloadInfo == null) {                       //参数1 appId应用编号                       String appId = data.id + "";                       //参数2 下载地址                       String url = ApiUrls.DOWNLOAD + data.downloadUrl;                       //参数3 文件名                       String fileName = data.name;                       //参数4 保存的绝对路径 String target = Environment.getExternalStorageDirectory().getAbsolutePath() + "/market/" + data.packageName + ".apk";                       //参数5 是否支持断点                       boolean autoResume = true;                       //参数6 是否重命名                       boolean autoRename = false;                       //参数回调对象,处理界面更新业务逻辑   mg.addNewDownload(appId, url, fileName, target, autoResume, autoRename, callback);                   } else {                       //继续传输                       //载按钮点击事件                       //loading当前出入下载状态                       if (downloadInfo.getState() == HttpHandler.State.LOADING) {                           mg.stopDownload(downloadInfo);                           part5BtnDownload.setText("继续");                       } else {                           mg.resumeDownload(downloadInfo, callback);                       }                   }               }catch(Exception e){e.printStackTrace();}            }        });

由于整个下载过程没有界面更新,用户不知道下载进度,所以编写进度更新的业务逻辑。编写在CallBack空方法里面

 RequestCallBack<File> callback= new RequestCallBack<File>(){       //下载过程中进度变化        @Override        public void onLoading(long total, long current, boolean isUploading) {            super.onLoading(total, current, isUploading);            //设置进度条的进度文本            //设置进度条最大值、设置当前进度            if(total==0){total=1;}            int percent = (int) (current*100f/total+0.5f);            BtnDownload.setText(percent+"%");            PbarProgress.setMax(100);//PbarProgress进度条            PbarProgress.setProgress(percent);        }        @Override        public void onSuccess(ResponseInfo<File> responseInfo) {            part5BtnDownload.setText("安装");            part5PbarProgress.setMax(100);            part5PbarProgress.setProgress(100);            //调用隐式意图安装            ApkUtil.install((Activity) context,responseInfo.result.getAbsolutePath());        }        @Override        public void onFailure(HttpException e, String s) {            part5BtnDownload.setText("继续");        }    };
/** *APK安装工具类 */public class ApkUtil {    public static void install(Activity activity,String target){        //Intent :开启服务或者打开页面        Intent intent = new Intent();        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        intent.setAction("android.intent.action.VIEW");        intent.addCategory("android.intent.category.DEFAULT");        String type = "application/vnd.android.package-archive";        // http://www.itheima.com f  /mnt/sdcard        Uri data = Uri.parse("file:///" + target);        intent.setDataAndType(data, type);        activity.startActivity(intent);    }}

进入页面需要进行回显(把断点记录下来,设置给界面)

 private void resumeDownLoadInfo(String appId) {        //5.1获取断点记录        DownloadInfo downloadInfo = mg.getDownloadInfoByAppId(appId);        if (downloadInfo == null) {            part5BtnDownload.setText("下载");            part5PbarProgress.setMax(100);            part5PbarProgress.setProgress(0);        } else {            //5.2计算百分比            long total = downloadInfo.getFileLength();            if (total == 0) {                total = 1;            }            int percent = (int) (downloadInfo.getProgress() * 100f / total + 0.5f);            part5PbarProgress.setMax(100);            part5PbarProgress.setProgress(percent);            if (downloadInfo.getState() == HttpHandler.State.LOADING) {                part5BtnDownload.setText(percent + "%");            } else {                part5BtnDownload.setText("继续");            }        }    }
0 0