整体的思路:

在下载文件时,将进度写入数据库,同一时候通知该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. nginx支持ssl双向认证配置

    nginx支持ssl双向认证配置 listen 443; server_name test.com; ssl on; ssl_certificate server.crt; //server端公钥 s ...

  2. 1195: [HNOI2006]最短母串

    思路:好像以前谁问过我这题...  状个压就好啦, 把包含在其他串中的字符串删掉, 预处理除每两个字符串之间的关系, dp[ state ][ i ] 表示在state的状态下, 最后一个字符串是第i ...

  3. kafka 基础知识梳理

    一.kafka 简介 kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据.这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因 ...

  4. NAT虚拟网络配置

     NAT虚拟网络配置(Linux能上网) 1.先设置虚拟机的虚拟网络,设置里面的子网ip和网关ip地址: 有两种方式:①setup命令(不选DHCP,因为它是动态分配IP地址的) ②vi /etc/s ...

  5. spark streaming限制吞吐

    使用spark.streaming.receiver.maxRate这个属性限制每秒的最大吞吐.官方文档如下: Maximum rate (number of records per second) ...

  6. CDM中添加Hive服务时Gateway是什么?

    参考这里http://grokbase.com/t/cloudera/scm-users/12aayq5cyh/what-is-gateway-in-cloudera-manager 实际上Gatew ...

  7. 纯CSS3实现蜡烛(冒烟)效果

    1. 闲来无事时在网上看一些前辈的博客文章,自己尝试了一下.学习到最重要的一点就是box-shadow的叠加使用,受益非线.先上一下效果图: 其中有以下重要的几点: 1. 蜡烛底座的border-ra ...

  8. 电子邮件-TCP

    参考下图,由于电子邮件是最早应用于网络上的服务,而早期网络的不可靠性,才设计了TCP协议,而邮件必须要保证正确传输,而非高速,所以早期的电子邮件协议 全是基于TCP的,一直持续到现在.

  9. Python学习——set集合的补充

    set 是一个无序且不重复的元素集合>>> num = {1,2,3,4,5} 1.add()添加一个元素 >>> num.add(6) >>> ...

  10. android studio svn 创建分支

    创建分支或标签 从哪里复制 工作副本 用这个变体去创建分支,并带着当地的改变.通常,服务项将被 添加带历史 , 不仅仅只有目标目录. 每个不同于根的版本文件 ,将被指定的复制.它推荐 去更新 工作副本 ...