android实用方法- - - -断点续传详解

最近遇到一点小需求,音乐下载,需要暂停下载,由于之前没有写过也是找了一些资源才搞懂的O(∩_∩)O哈哈~

首先要明确一点这个是需要后台支持的,也就是后台必须提供我们可以在某个字节开始下载的接口

下面我给大家说下基本思路,首先我们需要暂停下载,也就是我们需要在下载线程中中断下载,这个需要广播。然后就是我们的断点位置需要保存,所以我们需要实体类,并且我们需要存放在sqlite中方便增删改查。然后暂停之后我们从sqlite中取出上次的断点,向服务器请求实现断点下载。并且,在当前的文件的字节后开始下载实现断点续传。

android断点续传 切片 android断点续传原理面试_android

如上图所示基本上整个程序的逻辑

简答说下几个重要的点吧
首先你要有个保存当前下载位置的实体类

代码块

代码块语法遵循标准markdown代码,例如:

package com.example.nick.downloaddemo.entity;

/**
 * Created by Nick on 2017/2/7.
 * 线程信息
 */

public class ThreadInfo {
    private  int  id;
    private String url;
    private int start;//线程从哪里开始下载
    private int end;//下载到哪里结束
    private int finished;//完成了多少

    public ThreadInfo() {
    }

    public ThreadInfo(int id, String url, int start, int end, int finished) {
        this.id = id;
        this.url = url;
        this.start = start;
        this.end = end;
        this.finished = finished;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public int getStart() {
        return start;
    }

    public void setStart(int start) {
        this.start = start;
    }

    public int getEnd() {
        return end;
    }

    public void setEnd(int end) {
        this.end = end;
    }

    public int getFinished() {
        return finished;
    }

    public void setFinished(int finished) {
        this.finished = finished;
    }

    @Override
    public String toString() {
        return "ThreadInfo{" +
                "id=" + id +
                ", url='" + url + '\'' +
                ", start=" + start +
                ", end=" + end +
                ", finished=" + finished +
                '}';
    }
}

下面就需要sqlite来存储这些信息这个我就不贴了

然后你需要暂停下载 判断条件是传过来的 保存方法时工具类写好的

// 在下载暂停时,保存下载进度  终止下载
                        if (isPause)
                        {
                            mDao.updateThread(mThreadInfo.getUrl(), mThreadInfo.getId(), mFinised);
                            return;
                        }

最重也要的就是下载代码这里给出,就是不存在就创建,存在就取出

public void downLoad()
    {
        // 读取数据库的线程信息
        List<ThreadInfo> threads = mDao.getThreads(mFileInfo.getUrl());
        ThreadInfo threadInfo = null;

        if (0 == threads.size())
        {
            // 初始化线程信息对象
            threadInfo = new ThreadInfo(0, mFileInfo.getUrl(),
                    0, mFileInfo.getLength(), 0);
        }
        else
        {
            threadInfo = threads.get(0);
        }

        // 创建子线程进行下载
        new DownloadThread(threadInfo).start();
    }/** 
 * 下载线程 这里是断点续传的关键之一 
 * @author Yann 
 * @date 2015-8-8 上午11:18:55 
 */ 
 private class DownloadThread extends Thread 
 { 
 private ThreadInfo mThreadInfo = null;/**
     *@param mInfo
     */
    public DownloadThread(ThreadInfo mInfo)
    {
        this.mThreadInfo = mInfo;
    }

    /**
     * @see java.lang.Thread#run()
     */
    @Override
    public void run()
    {
        // 向数据库插入线程信息
        if (!mDao.isExists(mThreadInfo.getUrl(), mThreadInfo.getId()))
        {
            mDao.insertThread(mThreadInfo);
        }

        HttpURLConnection connection = null;
        RandomAccessFile raf = null;
        InputStream inputStream = null;

        try
        {
            URL url = new URL(mThreadInfo.getUrl());
            connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(5000);
            connection.setRequestMethod("GET");
            // 设置下载位置
            int start = mThreadInfo.getStart() + mThreadInfo.getFinished();
            Log.e("下载的位置",start+"");
            //设置下开始位置到结束的位置   setRequestProperty主要是设置HttpURLConnection请求头里面的属性  这个主要是看后台怎么写
            connection.setRequestProperty("Range",
                    "bytes=" + start + "-" + mThreadInfo.getEnd());
            // 设置文件写入位置
            File file = new File(DownloadService.DOWNLOAD_PATH,
                    mFileInfo.getFilename());
            raf = new RandomAccessFile(file, "rwd");
            //设置开始下载的位置   这是设置跳过多少个字节开始写入文件夹 例如raf.seek(10);就是跳过10个字节从11个字节开始
            raf.seek(start);
            Intent intent = new Intent();
            intent.setAction(DownloadService.ACTION_UPDATE);
            mFinised += mThreadInfo.getFinished();
            // 开始下载
            if (connection.getResponseCode() == 206)
            {
                // 读取数据
                inputStream = connection.getInputStream();
                byte buf[] = new byte[1024<<2];
                int len = -1;
                long time = System.currentTimeMillis();
                while ((len = inputStream.read(buf)) != -1)
                {
                    // 写入文件
                    raf.write(buf, 0, len);
                    // 把下载进度发送广播给Activity
                    mFinised += len;
                    if (System.currentTimeMillis() - time > 500)
                    {
                        Log.i("file——Start","发送广播");
                        time = System.currentTimeMillis();
                        intent.putExtra("finished", mFinised * 100 / mThreadInfo.getEnd());
                        mContext.sendBroadcast(intent);
                    }
                    // 在下载暂停时,保存下载进度  终止下载
                    if (isPause)
                    {
                        mDao.updateThread(mThreadInfo.getUrl(), mThreadInfo.getId(), mFinised);
                        return;
                    }
                }
                //最后一次可能小于500导致最后一次广播发不出去,进而不能显示完成100%
                Log.i("file——Start","发送广播");

                intent.putExtra("finished", mFinised * 100 / mThreadInfo.getEnd());
                mContext.sendBroadcast(intent);

                // 删除线程信息
                mDao.deleteThread(mThreadInfo.getUrl(), mThreadInfo.getId());
                Log.i("DownloadTask", "下载完毕");
                MainActivity.mMainActivity.handler.sendEmptyMessage(0);
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if (connection != null)
                {
                    connection.disconnect();
                }
                if (raf != null)
                {
                    raf.close();
                }
                if (inputStream != null)
                {
                    inputStream.close();
                }
            }
            catch (Exception e2)
            {
                e2.printStackTrace();
            }
        }
    }
}

以上就是下载的代码,上注释很清楚

// 设置下载位置 
 int start = mThreadInfo.getStart() + mThreadInfo.getFinished(); 
 Log.e(“下载的位置”,start+”“); 
 //设置下开始位置到结束的位置 setRequestProperty主要是设置HttpURLConnection请求头里面的属性 这个主要是看后台怎么写 
 connection.setRequestProperty(“Range”, 
 “bytes=” + start + “-” + mThreadInfo.getEnd());// 设置文件写入位置 
 File file = new File(DownloadService.DOWNLOAD_PATH, 
 mFileInfo.getFilename()); 
 raf = new RandomAccessFile(file, “rwd”); 
 //设置开始下载的位置 这是设置跳过多少个字节开始写入文件夹 例如raf.seek(10);就是跳过10个字节从11个字节开始 
 raf.seek(start);

这就实现了文件的断点拼接

这里会给出源码希望能帮助到你们( ⊙ o ⊙ )!