Android多线程下载

作者: Only凹凸曼 | 来源:发表于2017-02-12 11:42 被阅读188次

    背景

    万事都有两面性,多线程下载也是,那么多线程下载的优点是什么呢?归根结底还是多线程的优点,这里我们暂且不去讨论它的利弊,只是讲解一下思想和实现方案。

    实现分析

    我们用五个why的思想来分析一下这个问题:

    1. 怎么实现多线程下载?
      将下载逻辑在多个线程中同时运行。
    2. 怎么让每个线程下载对应的文件?
      将文件拆分成线程数对应的分数,进行分配。
    3. 怎么拆分文件?
      获取文件的长度,再按照线程数进行按比例分配。
    4. 怎么获取文件长度?
      利用HttpURLConnection的方法来获取内容长度
    5. 下载完成之后怎么办?
      各个线程都下载完成之后利用RandomAccessFile进行文件合并

    好了,分析到这我们感觉已经可以实现了,我们再重新梳理一下逻辑,大概是,设定线程的数量,按照线程数量来分割要下载的文件,启动多个线程进行下载,最后合成一个文件。OK,撸起袖子就是干!

    代码实现

    1、设置线程数,我这边是默认指定了三个,大家也可以通过服务器配置啊,或者某些算法来计算需要的线程数,根据实际情况来定。
    2、获取文件长度:

      URL url = new URL(file.url);
      HttpURLConnection con = (HttpURLConnection)
      url.openConnection();
      con.setRequestMethod("GET");
      con.setConnectTimeout(5000);
      if(con.getResponseCode() ==  HttpURLConnection.HTTP_OK) {
        int len = con.getContentLength(); //文件的总长度
      }
    

    这样我们就获取到了文件的长度,然后就可以分割下载了,当然之前我们要初始化一些路径啊,RandomAccessFile什么的,大家可以下载源码查看。
    3、分割文件内容:

            List<ThreadInfo> threadInfoList = new LinkedList<ThreadInfo>(); //建立线程信息列表
                int block = mDownloadInfo.lenght/mThreadCount; //将下载文件分段
                if(block > 0) {
                    //start 根据线程数量分别建立线程信息
                    for(int i = 0;i < mThreadCount;i++) {
                        ThreadInfo info = new ThreadInfo(i,mDownloadInfo.url,i*block,(i+1)*block-1,0);
                        if(i == mThreadCount -1) {
                            info.end = mDownloadInfo.lenght; //分段最后一个,结束位置到文件总长度末尾
                        }
                        threadInfoList.add(info);         //加入列表
                    }
                    //end 根据线程数量分别建立线程信息
    

    4、启动下载线程:

            //start 启动下载线程
            for(ThreadInfo info : threadInfoList) {
                DownloadThread thread = new DownloadThread(info,mDownloadInfo,mTotalFinished);
                if(!mThreadPool.isShutdown()) {
                    mThreadPool.execute(thread);
                }
    
            }
    

    5、下载的逻辑和RandomAccessFile最后生成一个完整的文件:

        public void run() {
            URL url = null;
            HttpURLConnection con = null;      //http链接
            RandomAccessFile accessFile = null; //下载文件
            InputStream inputStream = null;      //输入流
            try {
    
                int start = threadInfo.start+threadInfo.finished; //读取文件的位置
                //start 初始化下载链接
                url = new URL(threadInfo.url);
                con = (HttpURLConnection) url.openConnection();
                con.setRequestMethod("GET");
                con.setConnectTimeout(5000);
                con.setRequestProperty("Range", "bytes=" + start + "-" + threadInfo.end); //设置读取文件的位置,和结束位置
                //end 初始化下载链接
                //start 初始化下载到本地的文件
                accessFile  = new RandomAccessFile(new File(downloadInfo.filePath, downloadInfo.fileName),"rwd");
                accessFile.seek(start);    //设置开始写入的位置
                //end 初始化下载到本地的文件
    
                int responseCode = con.getResponseCode();
                if((con.getResponseCode() == HttpURLConnection.HTTP_PARTIAL) ||
                        (con.getResponseCode() == HttpURLConnection.HTTP_OK) ) {
                    inputStream = con.getInputStream();
                    int finished = threadInfo.finished;               //已经下载的长度
                    int readLen = -1;                                       //读取的长度
                    byte[] buffer = new byte[1024*4];
                    long time = System.currentTimeMillis();
    
                    //start 读取输入流写入文件
                    while((readLen = inputStream.read(buffer))!=-1) {
                        accessFile.write(buffer, 0, readLen);
                     );
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (ProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
    
                try {
                    if(inputStream!=null){
                        inputStream.close();
                    }
                    if(accessFile!=null) {
                        accessFile.close();
                    }
                    if(null!=con) {
                        con.disconnect();
                    }
    
                } catch (IOException e) {
                    e.printStackTrace();
                }
    
            }
            super.run();
        }
    
    

    总结

    好了,主要下载逻辑就是这样,大家想看完整代码的可以点击下面的链接,希望大家可以喜欢,谢谢!
    源码下载

    相关文章

      网友评论

      本文标题:Android多线程下载

      本文链接:https://www.haomeiwen.com/subject/obkaittx.html