整体的思路:

在下载文件时,将进度写入数据库,同一时候通知该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. idea中搜狗输入法不跟随光标,看不到输入的字

    好久没在windows上开发了,今天遇到一个比较坑的问题: 最新版idea,输入法都是最新的;但是idea里面输入字,看不到自己输入的是什么字,好坑... 在外面可以看到输入什么字说明与输入法无关, ...

  2. 查找网内活跃IP和自动传输文本

    ifconfig p32p1|egrep -o "broadcast [^ ]*" |grep -o "[0-9.]*"grep -o "broadc ...

  3. IntelliJ IDEA JRebel Maven Tomcat 实现热部署

    一,JRebel 插件 获取与安装 直接在 IDEA 中操作获取 JRebel 插件 Paste_Image.png Paste_Image.png 安装完成,记得重启 IDEA 使刚才安装的插件生效 ...

  4. MNMP下nginx1.6开启支持pathinfo配置,支持thinkphp的URL格式

    对于thinkphp框架项目的访问格式有多种,其中pathinfo是默认的基本访问格式,格式为:http://hostname:port/index.php/模块名/action名/参数1/参数1的值 ...

  5. Codeforces 280C Game on Tree 期望

    Game on Tree 这种题好像在wannfly训练营讲过, 我怎么又不会写啦, 我好菜啊啊啊. 我们按每个点算贡献, 一个点有贡献就说明它是被选中的点, 那么它被选中的概率就为1 / depth ...

  6. 配置Gitlab使用LDAP认证

    1. 通过SSH登陆Gitlab服务器. 2. 进行以下配置文件夹. [root@c720141 ~]# cd /etc/gitlab/ 3. 打开gitlab.rb配置文件,并加入以下配置. git ...

  7. QT5 QSS

    设计Qt程序Ui的时候,可以像WEB端使用CSS一样,使用QSS,使页面美化跟代码层分开,利于维护. 过程如下: 1.建立文本文件,写入样式表内容,更改文件后缀名为qss: 2.在工程中新建资源文件* ...

  8. 循序渐进学.Net Core Web Api开发系列【8】:访问数据库(基本功能)

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇讨论如 ...

  9. poj 3177 边双联通 **

    题意:给定一个连通的无向图G,至少要添加几条边,才能使其变为双连通图. 链接:点我 kuangbin模板题,分析链接:点我 #include <stdio.h> #include < ...

  10. hdu 5195 线段树

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABIgAAABeCAIAAADHZri1AAATWklEQVR4nO3dvU4jTRaA4b2nvgNzBw