zoukankan      html  css  js  c++  java
  • 用Service实现断点下载

    

    整体的思路:

    在下载文件时,将进度写入数据库,同一时候通知该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();
                }
            });
        }
    }

    
  • 相关阅读:
    flex布局简介
    未知宽高图片垂直居中
    网页设计中颜色应用
    webstorm10 注册码
    webapp尺寸
    【转】 svn 错误 以及 中文翻译
    css实现一个写信的格式
    使用::before和::after来完成尖角效果
    AI (Adobe Illustrator)详细用法(五)
    AI (Adobe Illustrator)详细用法(四)
  • 原文地址:https://www.cnblogs.com/hrhguanli/p/5101959.html
Copyright © 2011-2022 走看看