Android文件下载(实现断点续传)

本文将介绍在android平台下如何实现多线程下载,大家都知道,android平台使用java做为开发语言,所以java中支持的多线程下载方式在android平台下都支持,其中主要有两种方式可以实现多线程下载。
一种方式是使用很多个线程分别下载文件的不同部分,最后把所有下载完的文件合并成一个文件。另一种方式是使用java为我们提供的RandomAccessFile类实现多线程的下载。

从性能上分析,第二种方式的存取速度会慢一些,但开发起来较为容易,不需要进行合并文件等操作。本文将使用第二种方式来实现多线程下载,最终效果如下图所示:

使用图形界面来获取需要下载的内容,并实时更新下载进度条,代码如下所示:

    import java.io.File;
    import java.net.URL;
    import java.net.URLConnection;
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Environment;
    import android.os.Handler;
    import android.os.Message;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    /**
     *  Copyright (C) 2010 ideasandroid
     *  演示android多线程下载
     *  欢迎访问http://www.ideasandroid.com
     *  让程序开发不再那么神秘
     */
    public class FileDownloadDemo extends Activity {  

        private EditText downloadUrl;
        private EditText downloadFileName;
        private EditText downloadThreadNum;
        private Button downloadBt;
        private ProgressBar downloadProgressBar;
        private TextView progressMessage;
        private int downloadedSize = 0;
        private int fileSize = 0;  

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);  

            downloadUrl = (EditText) findViewById(R.id.downloadUrl);
            downloadFileName = (EditText) findViewById(R.id.downloadFileName);
            downloadThreadNum = (EditText) findViewById(R.id.downloadThreadNum);
            progressMessage = (TextView) findViewById(R.id.progressMessage);
            downloadBt = (Button) findViewById(R.id.downloadBt);
            downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);
            downloadProgressBar.setVisibility(View.VISIBLE);
            downloadProgressBar.setMax(100);
            downloadProgressBar.setProgress(0);
            downloadBt.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    download();
                }
            });
        }  

        private void download() {
            // 获取SD卡目录
            String dowloadDir = Environment.getExternalStorageDirectory()
                    + "/ideasdownload/";
            File file = new File(dowloadDir);
            //创建下载目录
            if (!file.exists()) {
                file.mkdirs();
            }  

            //读取下载线程数,如果为空,则单线程下载
            int downloadTN = Integer.valueOf("".equals(downloadThreadNum.getText()
                    .toString()) ? "1" : downloadThreadNum.getText().toString());
            //如果下载文件名为空则获取Url尾为文件名
            int fileNameStart = downloadUrl.getText().toString().lastIndexOf("/");
            String fileName = "".equals(downloadFileName.getText().toString()) ? downloadUrl
                    .getText().toString().substring(fileNameStart)
                    : downloadFileName.getText().toString();
            //开始下载前把下载按钮设置为不可用
            downloadBt.setClickable(false);
            //进度条设为0
            downloadProgressBar.setProgress(0);
            //启动文件下载线程
            new downloadTask(downloadUrl.getText().toString(), Integer
                    .valueOf(downloadTN), dowloadDir + fileName).start();
        }  

        Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                //当收到更新视图消息时,计算已完成下载百分比,同时更新进度条信息
                int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue();
                if (progress == 100) {
                    downloadBt.setClickable(true);
                    progressMessage.setText("下载完成!");
                } else {
                    progressMessage.setText("当前进度:" + progress + "%");
                }
                downloadProgressBar.setProgress(progress);
            }  

        };  

        /**
         * @author ideasandroid
         * 主下载线程
         */
        public class downloadTask extends Thread {
            private int blockSize, downloadSizeMore;
            private int threadNum = 5;
            String urlStr, threadNo, fileName;  

            public downloadTask(String urlStr, int threadNum, String fileName) {
                this.urlStr = urlStr;
                this.threadNum = threadNum;
                this.fileName = fileName;
            }  

            @Override
            public void run() {
                FileDownloadThread[] fds = new FileDownloadThread[threadNum];
                try {
                    URL url = new URL(urlStr);
                    URLConnection conn = url.openConnection();
                    //获取下载文件的总大小
                    fileSize = conn.getContentLength();
                    //计算每个线程要下载的数据量
                    blockSize = fileSize / threadNum;
                    // 解决整除后百分比计算误差
                    downloadSizeMore = (fileSize % threadNum);
                    File file = new File(fileName);
                    for (int i = 0; i < threadNum; i++) {
                        //启动线程,分别下载自己需要下载的部分
                        FileDownloadThread fdt = new FileDownloadThread(url, file,
                                i * blockSize, (i + 1) * blockSize - 1);
                        fdt.setName("Thread" + i);
                        fdt.start();
                        fds[i] = fdt;
                    }
                    boolean finished = false;
                    while (!finished) {
                        // 先把整除的余数搞定
                        downloadedSize = downloadSizeMore;
                        finished = true;
                        for (int i = 0; i < fds.length; i++) {
                            downloadedSize += fds[i].getDownloadSize();
                            if (!fds[i].isFinished()) {
                                finished = false;
                            }
                        }
                        //通知handler去更新视图组件
                        handler.sendEmptyMessage(0);
                        //休息1秒后再读取下载进度
                        sleep(1000);
                    }
                } catch (Exception e) {  

                }  

            }
        }
    }  
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;

import android.util.Log;
/**
 *  Copyright (C) 2010 ideasandroid
 *  演示android多线程下载
 *  欢迎访问http://www.ideasandroid.com
 *  让程序开发不再那么神秘
 *
 *  单个下载线程
 */
public class FileDownloadThread extends Thread{
    private static final int BUFFER_SIZE=1024;
    private URL url;
    private File file;
    private int startPosition;
    private int endPosition;
    private int curPosition;
    //用于标识当前线程是否下载完成
    private boolean finished=false;
    private int downloadSize=0;
    public FileDownloadThread(URL url,File file,int startPosition,int endPosition){
        this.url=url;
        this.file=file;
        this.startPosition=startPosition;
        this.curPosition=startPosition;
        this.endPosition=endPosition;
    }
    @Override
    public void run() {
        BufferedInputStream bis = null;
        RandomAccessFile fos = null;
        byte[] buf = new byte[BUFFER_SIZE];
        URLConnection con = null;
        try {
            con = url.openConnection();
            con.setAllowUserInteraction(true);
            //设置当前线程下载的起点,终点
            con.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition);
            //使用java中的RandomAccessFile 对文件进行随机读写操作
            fos = new RandomAccessFile(file, "rw");
            //设置开始写文件的位置
            fos.seek(startPosition);
            bis = new BufferedInputStream(con.getInputStream());
            //开始循环以流的形式读写文件
            while (curPosition < endPosition) {
                int len = bis.read(buf, 0, BUFFER_SIZE);
                if (len == -1) {
                    break;
                }
                fos.write(buf, 0, len);
                curPosition = curPosition + len;
                if (curPosition > endPosition) {
                    downloadSize+=len - (curPosition - endPosition) + 1;
                } else {
                    downloadSize+=len;
                }
            }
            //下载完成设为true
            this.finished = true;
            bis.close();
            fos.close();
        } catch (IOException e) {
          Log.d(getName() +" Error:", e.getMessage());
        }
    }

    public boolean isFinished(){
        return finished;
    }

    public int getDownloadSize() {
        return downloadSize;
    }
}

Andorid多线程断点续传下载器:http://www.jcodecraeer.com/a/opensource/2015/0602/2978.html

时间: 2024-08-23 03:17:23

Android文件下载(实现断点续传)的相关文章

Android实现多线程断点续传

前言: 项目都快交付阶段了,客户说要改个需求,添加一个断点续传功能.在版本更新,杂志下载或者视频下载的时候实现断点续传.由于时间紧迫,想起了之前研究过一个demo代码,就直接修改使用了,根据自己的方式实现,但是核心代码没变.以后或许会用到,于是就专门写了个demo. 先看一下项目目录结构: db--->操作数据库的(创建数据库表,数据的增删改查.) util--->工具类 download--->实现下载(下载器以及自定义线程.) 这里以易信客户端的下载为例,简要介绍. String d

Rxjava+ReTrofit+okHttp深入浅出-终极封装四(多文件下载之断点续传)

Rxjava+ReTrofit+okHttp深入浅出-终极封装四(多文件下载之断点续传) 背景 断点续传下载一直是移动开发中必不可少的一项重要的技术,同样的Rxjava和Retrofit的结合让这个技术解决起来更加的灵活,我们完全可以封装一个适合自的下载框架,简单而且安全! 效果 实现 下载和之前的http请求可以相互独立,所以我们单独给download建立一个工程moudel处理 1.创建service接口 和以前一样,先写接口 注意:Streaming是判断是否写入内存的标示,如果小文件可以

Android文件下载之进度检测

近期因为项目的需要,研究了一下Android文件下载进度显示的功能实现,接下来就和大家一起分享学习一下,希望对广大初学者有帮助. 先上效果图: 上方的蓝色进度条,会根据文件下载量的百分比进行加载,中部的文本控件用来现在文件下载的百分比,最下方的ImageView用来展示下载好的文件,项目的目的就是动态向用户展示文件的下载量. 下面看代码实现:首先是布局文件: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/

文件下载之断点续传(客户端与服务端的实现)

原文:http://www.cnblogs.com/zhaopei/p/download.html 阅读目录 文件下载-服务端 使用a标签提供文件下载 使用Response.TransmitFile提供文件下载 其他方式文件下载 文件下载-客户端 直接下载 异步下载 断点续传 断点续传(服务端的支持) 多线程同时下载(分片下载) 前面讲了文件的上传,今天来聊聊文件的下载. 老规矩,还是从最简单粗暴的开始.那么多简单算简单?多粗暴算粗暴?我告诉你可以不写一句代码,你信吗?直接把一个文件往IIS服务

Android多线程下载断点续传

先上图看卡结果: GITHUB:Android多线程下载断点续传 如图所示点击下载就开始下载,点击停止就会停止再次点击下载就会接着下载了. 设计思路是这样的: 首先通过广播将下载信息传递给DownService,DownService根据文件URL获取文件大小,再通过DownTask将下载任务分配,并且通过广播当点击停止下载时将下载进度保存在数据库中,当点击开始下载时再从数据库中获取到保存的进度,继续下载. 代码结构: 核心类是 DownLoadService,java 和DownTask.ja

android 文件下载及进度条显示

android 文件下载 进度条: ProgressDialog progress = new ProgressDialog(context); progress.setTitle(“文件下载”); progress.setMessage("loading..."); progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progress.setIndeterminate(false);//设置为fase等待进度更新,设

【转】文件下载之断点续传(客户端与服务端的实现)

[转]文件下载之断点续传(客户端与服务端的实现) [转]文件下载之断点续传(客户端与服务端的实现) 前面讲了文件的上传,今天来聊聊文件的下载. 老规矩,还是从最简单粗暴的开始.那么多简单算简单?多粗暴算粗暴?我告诉你可以不写一句代码,你信吗?直接把一个文件往IIS服务器上一扔,就支持下载.还TM么可以断点续传(IIS服务端默认支持). 在贴代码之前先来了解下什么是断点续传(这里说的是下载断点续传)?怎么实现的断点续传?断点续传就是下载了一半断网或者暂停了,然后可以接着下载.不用从头开始下载. 很

android 细数断点续传的坑

android项目中,不可避免会下载一些第三方应用,或者自身更新的包,或者下载视频文件,那么都会考虑用到断线续传的方式. 那么,断电续传的方式大概有3种: 1.比如下载视频的时候,调用js的方法,把文件下载下来,然后用randomAccessFile合并成一个文件. 2.如xUtils的断点续传代码,具体自己看. 3.利用sqlite,配合上randomAccessFile来实现. 第一种主要是用于下载视频,为啥呢,因为考虑到网络问题之类的,频繁的断点和续传,有概率性出现花屏等,用后面2中会出现

C# 文件下载之断点续传

注意,本文所说的断点续传特指 HTTP 协议中的断点续传.本文主要聊聊思路和关键代码,更多细节请参考本文附带的 demo. 工作原理 HTTP 协议中定义了一些请求/响应头,通过组合使用这些头信息.我们可以在一次 HTTP 请求中只请求一个文件中的一部分数据.这样我们就可以把已经下载的数据存起来,下次只用请求剩余的数据即可,当全部数据都下载到本地后再完成合并工作. HTTP 协议指出,可以通过 HTTP 请求中的 Range 头指定请求数据的范围,Range 头的使用也很简单,只要指定下面的格式