整体的思路:

在下载文件时,将进度写入数据库,同一时候通知该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. python多个分割符split字符串

    python中string自带的split不支持多个分隔符同时切分,用正则 import re line='hello,world' lineLists = re.split('[,,..??]',l ...

  2. Java多态概述

    多态 所谓多态,实际上就是一个对象的多种状态: 下面例子中,Tiger可以看做Tiger,也可以看做Animal Cat  可以看做Cat,也可以看做Animal Dog 可以看做Dog,也可以看做A ...

  3. java 编译与运行

    javac  编译 .java文件 javac file.java //将file.java 编译为 file.classjavac -d folder file.java //将file.java ...

  4. php常用的安全过滤函数

    目录结构 ①常用的安全函数有哪些: ②这些函数的作用: ③函数的用法: ④举例说明: ⑤参考资料: 由于越来越多的项目开始使用框架,所以,很多的程序员也不在关心安全的问题!因为框架已经帮我们几乎完美的 ...

  5. <转> 解决异常:IllegalStateException: Fragment <ThisFragment> is not currently in the FragmentManager

    上午敲代码时出现这个问题,简单记录一下解决办法,有时间详细描述一下深层原因. 问题出现在这: @Override public void onSaveInstanceState(Bundle outS ...

  6. SQL Server 4

    一.视图 1.创建视图 1)选中数据库中的表中的视图处,右键选择新建视图,即: 2)在弹出“添加表”对话框中,单击“表”标签,选择要添加的表,点击添加,即: 3)选中要建立联系的列名的复选框,然后拖动 ...

  7. 如何写django中form的测试用例

    可简可繁, 可插库,可字符, 要测试valid,也要测试invalid, 可用csrf,也可用context. 放一个全面的, 实践中,找一个最优的组合就好. class NewTopicTests( ...

  8. webstorm减少内存占用

    首先,按照我说的设置之后要重启才行. 在项目里找到不需要监听的文件夹右键:Mark Directory As => Cancel Exclusion 然后重启,嘿嘿,成功了!

  9. String、Date和Timestamp的互转

    begin 2018年8月17日19:09:49 String.Date和Timestamp的互转 String和Date的互转 关于String和Date的互转,在java8后会有不同.因为java ...

  10. Java NIO -2

    NIO http://www.cnblogs.com/puyangsky/p/5840873.html -- 操作系统与 Java 基于流的 I/O模型有些不匹配.操作系统要移动的是大块数据(缓冲区) ...