整体的思路:

在下载文件时,将进度写入数据库,同一时候通知该ContentProvider的观察者更新页面,这个通知过程不要太频繁。我设置了10次,否则页面会灰常卡。

假设异常中断(网络中断或程序被kill)也没有关系。由于数据库中有记录,仅仅要从该文件的断点位置继续下载就能够了。关键在于一切以数据库为准

就能够了。

同一时候要注意的是:

1、自始至终处理的都是同一个PO对象,没有直接用类的成员变量,由于下次启动线程。成员变量会变化,导致诡异的下载文件不正确应。

2、启动线程后,将该线程保存进static类变量 downloaders 里,方便在Service类外进行停止线程。

3、由于有一个或多个下载进度的页面。所以在下载更新数据库的同一时候。进行了通知观察者的操作。当然也能够有其它的方法,比方,

1)在Activity里加入一个线程时刻扫描数据库等等,只是感觉没有这个好。

2)也实用更新进度的时候,不断发广播的方式,在Activity中注冊广播接收者更新页

大家有更好的办法请回复。

红色字体部分为关键。其它都是浮云。

/**

 *

 * 因为该Service用于多线程下载文件,须要确保原子性。一直处理一个DownLoadFilePO对象

 *

 * <p>detailed comment

 * @see

 * @since 1.0

 */

public class DownLoadService extends Service {

    private static final String TAG = "DownLoadFileService";

    private String downloadUrl;

    private boolean showToast;

    public static Map<String, DownLoadThread> downloaders = new HashMap<String, DownLoadThread>();

@Override

    public IBinder onBind(Intent arg0) {

        return null;

    }

@Override

    public void onCreate() {

        //仅仅运行一次

        super.onCreate();

    }

@Override

    @Deprecated

    public void onStart(Intent intent, int startId) {

        super.onStart(intent, startId);

        if (intent == null) {

            return;

        }

        downloadUrl = intent.getStringExtra("downloadUrl");

        showToast = intent.getBooleanExtra("showToast", false);

DownLoadThread downLoadThread = new DownLoadThread(downloadUrl);

        Thread thread = new Thread(downLoadThread);

        thread.start();

}

/**

     *

     * 下载线程

     *

     * <p>detailed comment

     * @see

     * @since 1.0

     */

    public class DownLoadThread implements Runnable {

        String url;

        boolean downloading = true;

DownLoadThread(String downloadUrl) {

            this.url = downloadUrl;

        }

/**

         * 终止线程

         */

        public void stop() {

            this.downloading = false;

        }

@Override

        public void run() {

            //查看是否已经在下载

            DownLoadFilePO po = queryByDownLoadUrl(url);

            if (po != null) {

if (showToast) {

                    showToast(getResources().getString(R.string.this_file_is_downloaded));

                } else {

                    downloaders.put(downloadUrl, this);

                    showToast(getResources().getString(R.string.this_file_begin_download));

                    download(po);

                }

            } else {

                po = init(url);

                initProgress(po);

                downloaders.put(downloadUrl, this);

                download(po);

            }

        }

/**

         * 下载

         */

        private void download(DownLoadFilePO po) {

            HttpURLConnection connection = null;

            RandomAccessFile randomAccessFile = null;

            InputStream is = null;

            try {

                URL url = new URL(downloadUrl);

                connection = (HttpURLConnection) url.openConnection();

                connection.setConnectTimeout(5000);

                connection.setRequestMethod("GET");

                // 设置远程文件的下载范围。格式为Range:bytes x-y;

                connection.setRequestProperty("Range",

                        "bytes=" + po.getCurrent_size() + "-" + po.getTotal_size());

                //设置本地文件的下载開始位置

                File localFile = new File(po.getFile());

                randomAccessFile = new RandomAccessFile(localFile, "rwd");

                randomAccessFile.seek(po.getCurrent_size());

                is = connection.getInputStream();

                byte[] buffer = new byte[1024000];

                int length = -1;

                int count = 0;

                while ((length = is.read(buffer)) != -1) {

                    randomAccessFile.write(buffer, 0, length);

                    // 更新数据库中的下载信息

                    po.setCurrent_size(po.getCurrent_size() + length);

                    updateProgress(po);

                    // 用消息将下载信息传给进度条,对进度条进行更新

                    count++;

                    if (count % 10 == 0) {

                        getContentResolver().notifyChange(ConstantUtil.uri, null);//假设改变数据。则通知全部人

                        Log.v(TAG, po.getName() + "=======下载进度======" + po.getCurrent_size());

                    }

                    if (!downloading) {

                        Log.v(TAG, po.getName() + "=======暂停====" + po.getCurrent_size());

                        downloaders.remove(po.getDownloadUrl());

                        return;

                    }

                }

                //下载完毕

                if (po.getCurrent_size() == po.getTotal_size()) {

                    finishProgress(po);

                }

                downloaders.remove(po.getDownloadUrl());

            } catch (Exception e) {

                getContentResolver().notifyChange(ConstantUtil.uri, null);//假设改变数据,则通知全部人

                this.stop();

                e.printStackTrace();

            } finally {

                try {

                    is.close();

                    randomAccessFile.close();

                    connection.disconnect();

                } catch (Exception e) {

                    e.printStackTrace();

                }

            }

        }

    }

/**

     * 初始化

     */

    private DownLoadFilePO init(String downloadUrl) {

        DownLoadFilePO po = new DownLoadFilePO();

try {

            if (!FileUtil.checkFileDir()) {

                return null;

            }

URL url = new URL(downloadUrl);

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            connection.setConnectTimeout(5000);

            connection.setRequestMethod("GET");

            int fileSize = connection.getContentLength();

            //总大小

            String fileName = FileUtil.getFileNameByUrl(downloadUrl);

            try {

                fileName = URLDecoder.decode(fileName, "UTF-8");

            } catch (UnsupportedEncodingException e) {

                Log.e(TAG, e.getMessage());

            }

            File localFile = new File(ConstantUtil.downloadFileDir + fileName);

            //推断同名文件已经存在。如存在同名的文件。需改动文件名 sample.mp4 ==>sample(1).mp4

            int i = 1;

            while (localFile.exists()) {

                int index = fileName.lastIndexOf(".");

                fileName = fileName.substring(0, index) + "(" + i + ")"

                        + fileName.substring(index, fileName.length());

                localFile = new File(ConstantUtil.downloadFileDir + fileName);

                i++;

            }

            localFile.createNewFile();

            i = 0;

            //            }

            // 本地訪问文件

            RandomAccessFile accessFile = new RandomAccessFile(localFile, "rwd");

            accessFile.setLength(fileSize);

            accessFile.close();

            connection.disconnect();

po.setName(fileName);

            po.setDownloadUrl(downloadUrl);

            po.setCurrent_size(0L);

            po.setTotal_size(fileSize);

            po.setFile(localFile.getAbsolutePath());

        } catch (Exception e) {

            e.printStackTrace();

        }

        return po;

    }

/**

     * 向数据库中插入初始化数据

     */

    private void initProgress(DownLoadFilePO po) {

        ContentValues values = new ContentValues();

        values.put(DataBaseUtil.DOWNLOAD_FILE_NAME, po.getName());

        values.put(DataBaseUtil.CREATE_FILE_DATE, new Date().toString());

        values.put(DataBaseUtil.DOWNLOAD_FILE_TOTAL_SIZE, po.getTotal_size());

        values.put(DataBaseUtil.DOWNLOAD_FILE_CURRENT_SIZE, 0);

        values.put(DataBaseUtil.DOWNLOAD_FINISHED, false);

        values.put(DataBaseUtil.DOWNLOAD_URL, po.getDownloadUrl());

        values.put(DataBaseUtil.DONWLOAD_FILE_PATH, po.getFile());

this.getContentResolver().insert(ConstantUtil.uri, values); //向ContentProvider插入数据 

    }

/**

     *

     * 更新进度

     *

     *<p>detail comment

     *@see

     *@since

     *

     */

    private void updateProgress(DownLoadFilePO po) {

        ContentValues values = new ContentValues();

        values.put(DataBaseUtil.DOWNLOAD_FILE_CURRENT_SIZE, po.getCurrent_size());

        this.getContentResolver().update(ConstantUtil.uri, values,

                DataBaseUtil.DOWNLOAD_URL + "=?

", new String[] { po.getDownloadUrl() });

    }

/**

     *

     * 完毕下载

     *

     *<p>detail comment

     *@param currentSize

     *@see

     *@since

     *

     */

    private void finishProgress(DownLoadFilePO po) {

        ContentValues values = new ContentValues();

        values.put(DataBaseUtil.DOWNLOAD_FILE_CURRENT_SIZE, po.getTotal_size());

        values.put(DataBaseUtil.DOWNLOAD_FINISHED, true);

this.getContentResolver().update(ConstantUtil.uri, values,

                DataBaseUtil.DOWNLOAD_URL + "=?

", new String[] { po.getDownloadUrl() });

        getContentResolver().notifyChange(ConstantUtil.uri, null);

    }

/**

     *

     * 查看该url是否在下载

     *

     *<p>detail comment

     *@param url

     *@return

     *@see

     *@since

     *

     */

    private DownLoadFilePO queryByDownLoadUrl(String url) {

        Cursor cursor = this.getContentResolver().query(

                ConstantUtil.uri,

                new String[] { DataBaseUtil.DOWNLOAD_FILE_NAME,

                        DataBaseUtil.DOWNLOAD_FILE_CURRENT_SIZE,

                        DataBaseUtil.DOWNLOAD_FILE_TOTAL_SIZE, DataBaseUtil.DONWLOAD_FILE_PATH,

                        DataBaseUtil.DOWNLOAD_FINISHED }, DataBaseUtil.DOWNLOAD_URL + "=?",

                new String[] { url }, null);

        if (cursor.moveToNext()) {

            DownLoadFilePO po = new DownLoadFilePO();

            for (int i = 0; i < cursor.getCount(); i++) {

                cursor.moveToPosition(i);

                po.setName(cursor.getString(0));

                po.setCurrent_size(cursor.getLong(1));

                po.setTotal_size(cursor.getLong(2));

                po.setFile(cursor.getString(3));

                po.setDownloadUrl(url);

            }

            return po;

        }

return null;

    }

private void showToast(final String toast) {

        Handler handler = new Handler(Looper.getMainLooper());

        handler.post(new Runnable() {

            public void run() {

                Toast.makeText(DownLoadService.this, toast, Toast.LENGTH_SHORT).show();

            }

        });

    }

}



用Service实现断点下载的更多相关文章

  1. 安卓(android)之实现断点下载功能

    一.建立实体类 1.文件实体类 package com.example.zjw.myapplication.dao; import java.io.Serializable; /** * 预下载文件实 ...

  2. Retrofit 2.0 超能实践(四),完成大文件断点下载

    作者:码小白 文/CSDN 博客 本文出自:http://blog.csdn.net/sk719887916/article/details/51988507 码小白 通过前几篇系统的介绍和综合运用, ...

  3. andoid 多线程断点下载

    本示例介绍在Android平台下通过HTTP协议实现断点续传下载. 我们编写的是Andorid的HTTP协议多线程断点下载应用程序.直接使用单线程下载HTTP文件对我们来说是一件非常简单的事.那么,多 ...

  4. Android学习笔记_15_网络通信之文件断点下载

    一.断点下载原理: 使用多线程下载文件可以更快完成文件的下载,多线程下载文件之所以快,是因为其抢占的服务器资源多.如:假设服务器同时最多服务100个用户,在服务器中一条线程对应一个用户,100条线程在 ...

  5. 我的Android进阶之旅------>Android基于HTTP协议的多线程断点下载器的实现

    一.首先写这篇文章之前,要了解实现该Android多线程断点下载器的几个知识点 1.多线程下载的原理,如下图所示 注意:由于Android移动设备和PC机的处理器还是不能相比,所以开辟的子线程建议不要 ...

  6. Java实现多线程断点下载(下载过程中可以暂停)

    线程可以理解为下载的通道,一个线程就是一个文件的下载通道,多线程也就是同时开启好几个下载通道.当服务器提供下载服务时,使用下载者是共享带宽的,在优先级相同的情况下,总服务器会对总下载线程进行平均分配. ...

  7. iOS 大文件断点下载

    iOS 在下载大文件的时候,可能会因为网络或者人为等原因,使得下载中断,那么如何能够进行断点下载呢? // resumeData的文件路径 #define XMGResumeDataFile [[NS ...

  8. 【Java EE 学习 22 下】【单线程下载】【单线程断点下载】【多线程下载】

    一.文件下载简述 1.使用浏览器从网页上下载文件,Servlet需要增加一些响应头信息 (1)response.setContentType("application/force-downl ...

  9. IOS 断点下载

    // // ViewController.m // UI4_断点下载 // // Created by qianfeng on 15/8/19. // Copyright (c) 2015年 ZBC. ...

随机推荐

  1. mysql innodb 行级锁升级

    创建数据表test,表定义如下所示: CREATE TABLE `test` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NO ...

  2. input标签的事件汇总

    我在做一个注册时用到了,在网上查的,比较碎.就汇总了下, 1.onfocus  当input 获取到焦点时触发 2.onblur  当input失去焦点时触发,注意:这个事件触发的前提是已经获取了焦点 ...

  3. HTTP 和 HTTPS 的异同

    什么是 HTTPS? HTTPS (基于安全套接字层的超文本传输协议 或者是 HTTP over SSL) 是一个 Netscape 开发的 Web 协议. 你也可以说:HTTPS = HTTP + ...

  4. MAC下调试JSON接口的工具(HTTP抓包工具)

    MAC下的HTTP接口抓包工具,专业级: 专门做JSON接口测试的工具,简单好用!

  5. 如果django里的视图是类(CBV),应该如何写Url的测试用例?

    晚上回家测试了很多方式,都不行. 网上搜索找不到答案, 最后还是官方文档最抵用呢. https://docs.djangoproject.com/en/2.1/topics/testing/tools ...

  6. linux网络管理基本命令

    1.last 显示所有用户的登录情况 2.lastlog 显示那些用户有登录过,那些用户从来没登录过 3.traceroute 探测我指定网站的路径,来跟踪路由 .如:traceroute   www ...

  7. vue1.0

    vue1.0学习总结   前言 使用vue已经有三.四个月了,但是只是学着使用了一些基本方法.因为现在的前端框架越来越多(Angular,React...),但是我相信万变不离其宗,很多用法框架之间还 ...

  8. JPA学习

    [JPA 简介]JPA(Java Persistence API) JPA 不是一个ORM 的框架, 而是一个ORM 的规范,只指定了一些接口, 具体的实现由应用服务器厂商来提供实现. JPA的实现产 ...

  9. SpringBoot中使用纯scala进行开发 配置教程 非常简单的案例

    新建项目 建好之后 建一个叫scala的文件夹 并把它标记为root文件夹 修改pom.xml文件 复制粘贴如下内容: 添加的插件的作用,如果不添加,在新建文件的时候右键只能新建java的文件,无法创 ...

  10. 010 使用jquery实现小需求练习-------对应选择器的练习

    1.需求 点击所有的 p 节点, 能够弹出其对应的文本内容 使第一个 table 隔行变色 点击 button, 弹出 checkbox 被选中的个数 2.程序 <!DOCTYPE html&g ...