android多线程断点下载-带进度条和百分比进度显示效果

发布时间 - 2026-01-11 01:45:36    点击率:

android多线程断点下载,带进度条和百分比显示,断点下载的临时数据保存到SD卡的文本文档中,建议可以保存到本地数据库中,这样可以提高存取效率,从而提高系统性能。

效果:

打开软件:

下载中:

下载完毕:

附代码如下:

package com.yy.multiDownloadOfBreakPoint;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
/**
 * 多线程断点下载实例
 * @author YUANYUAN
 *
 */
public class MainActivity extends Activity {
  //下载所使用的线程数
  protected static final int threadCount = 3;
  //下载完毕的标记
  public static final int downloadOver = 1;
  //更新下载进度标记
  public static final int UPDATE_PROGRESS = 0;
  //下载资源的路径输入框
  private EditText et_path;
  //下载的进度条
  private ProgressBar pb;
  //进度显示
  private TextView tv_pb;
  //当前累计下载的数据
  int curDownCount=0;
  //当前活动的下载线程数
  protected static int activeThread;
  //加入消息处理机制
  private Handler handler=new Handler(){
    @Override
    public void handleMessage(Message msg) {
      switch (msg.what) {
      case downloadOver:
        Toast.makeText(MainActivity.this, "文件已下载完毕!", Toast.LENGTH_LONG).show();
        tv_pb.setText("下载完成");
        break;
      case UPDATE_PROGRESS:
        //更新进度显示
        tv_pb.setText("当前进度:"+(pb.getProgress()*100/pb.getMax())+"%");
        break;
      default:
        break;
      }
    }
  };

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    et_path=(EditText) findViewById(R.id.et_path);
    et_path.setText("http://192.168.2.114:8080/sqlite.exe");
    pb=(ProgressBar) findViewById(R.id.pb);
    tv_pb=(TextView) findViewById(R.id.tv_pb);
  }
  
  /**
   * 开始下载
   * @param view
   */
  public void down(View view){
    //获取下载资源的路径
    final String path=et_path.getText().toString().trim();
    //判断资源路径是否为空
    if (TextUtils.isEmpty(path)) {
      Toast.makeText(this, "请输入下载资源的路径", Toast.LENGTH_LONG).show();
      return;
    }
    //开启一个线程进行下载
    new Thread(){
      public void run() {
        try {
          //构造URL地址
          URL url=new URL(path);
          //打开连接
          HttpURLConnection conn=(HttpURLConnection) url.openConnection();
          //设置请求超时的时间
          conn.setConnectTimeout(5000);
          //设置请求方式
          conn.setRequestMethod("GET");
          //获取相应码
          int code=conn.getResponseCode();
          if (code==200) {//请求成功
            //获取请求数据的长度
            int length=conn.getContentLength();
            //设置进度条的最大值
            pb.setMax(length);
            //在客户端创建一个跟服务器文件大小相同的临时文件
            RandomAccessFile raf=new RandomAccessFile("sdcard/setup.exe", "rwd");
            //指定临时文件的长度
            raf.setLength(length);
            raf.close();
            //假设3个线程去下载资源
            //平均每一个线程要下载的文件的大小
            int blockSize=length/threadCount;
            for (int threadId = 1; threadId <= threadCount; threadId++) {
              //当前线程下载数据的开始位置
              int startIndex=blockSize*(threadId-1);
              //当前线程下载数据的结束位置
              int endIndex=blockSize*threadId-1;
              //确定最后一个线程要下载数据的最大位置
              if (threadId==threadCount) {
                endIndex=length;
              }
              //显示下载数据的区间
              System.out.println("线程【"+threadId+"】开始下载:"+startIndex+"---->"+endIndex);
              //开启下载的子线程
              new DownloadThread(path, threadId, startIndex, endIndex).start();
              //当前下载活动的线程数加1
              activeThread++;
              System.out.println("当前活动的线程数:"+activeThread);
            }
            
          }else{//请求失败
            System.out.println("服务器异常,下载失败!");
          }
        } catch (Exception e) {
          e.printStackTrace();
          System.out.println("服务器异常,下载失败!");
        }
      };
    }.start();
    
  }
  /**
   * 下载文件的子线程 每一个文件都下载对应的数据
   * @author YUANYUAN
   *
   */
  public class DownloadThread extends Thread{
    private String path;
    private int threadId;
    private int startIndex;
    private int endIndex;
    
    /**
     * 构造方法
     * @param path 下载文件的路径
     * @param threadId 下载文件的线程
     * @param startIndex 下载文件开始的位置
     * @param endIndex 下载文件结束的位置
     */
    public DownloadThread(String path, int threadId, int startIndex,
        int endIndex) {
      this.path = path;
      this.threadId = threadId;
      this.startIndex = startIndex;
      this.endIndex = endIndex;
    }



    @Override
    public void run() {
      //构造URL地址
      try {
        
        File tempFile=new File("sdcard/"+threadId+".txt");
        //检查记录是否存在,如果存在读取数据,设置真实下载开始的位置
        if (tempFile.exists()) {
          FileInputStream fis=new FileInputStream(tempFile);
          byte[] temp=new byte[1024];
          int length=fis.read(temp);
          //读取到已经下载的位置
          int downloadNewIndex=Integer.parseInt(new String(temp, 0, length));
          //计算出已经下载的数据长度
          int areadyDown=downloadNewIndex-startIndex;
          //累加已经下载的数据量
          curDownCount+=areadyDown;
          //设置进度条已经下载的数据量
          pb.setProgress(curDownCount);
          //设置重新开始下载的开始位置
          startIndex=downloadNewIndex;
          fis.close();
          //显示真实下载数据的区间
          System.out.println("线程【"+threadId+"】真实开始下载数据区间:"+startIndex+"---->"+endIndex);
        }
        
        URL url = new URL(path);
        HttpURLConnection conn=(HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5000);
        conn.setRequestMethod("GET");
        //设置请求属性,请求部分资源
        conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
        int code=conn.getResponseCode();
        if (code==206) {//下载部分资源,正常返回的状态码为206
          InputStream is=conn.getInputStream();//已经设置了请求的位置,所以返回的是对应的部分资源
          //构建随机访问文件
          RandomAccessFile raf=new RandomAccessFile("sdcard/setup.exe", "rwd");
          //设置 每一个线程随机写文件开始的位置
          raf.seek(startIndex);
          //开始写文件
          int len=0;
          byte[] buffer=new byte[1024];
          //该线程已经下载数据的长度
          int total=0;
          
          while((len=is.read(buffer))!=-1){//读取输入流
            //记录当前线程已下载数据的长度
            RandomAccessFile file=new RandomAccessFile("sdcard/"+threadId+".txt","rwd");
            raf.write(buffer,0,len);//写文件
            total+=len;//更新该线程已下载数据的总长度
            System.out.println("线程【"+threadId+"】已下载数据:"+(total+startIndex));
            //将已下载数据的位置记录写入到文件
            file.write((startIndex+total+"").getBytes());
            //累加已经下载的数据量
            curDownCount+=len;
            //更新进度条【进度条的更新可以在非UI线程直接更新,具体见底层源代码】
            pb.setProgress(curDownCount);
            
            //更新下载进度
            Message msg=Message.obtain();
            msg.what=UPDATE_PROGRESS;
            handler.sendMessage(msg);
            
            file.close();
          }
          is.close();
          raf.close();
          //提示下载完毕
          System.out.println("线程【"+threadId+"】下载完毕");
        }
      } catch (Exception e) {
        e.printStackTrace();
        System.out.println("线程【"+threadId+"】下载出现异常!!");
      }finally{
        //活动的线程数减少
        activeThread--;
        if (activeThread==0) {
          for (int i = 1; i <= threadCount; i++) {
            File tempFile=new File("sdcard/"+i+".txt");
            tempFile.delete();
          }
          System.out.println("下载完毕,已清除全部临时文件");
          //界面消息提示下载完毕
          Message msg=new Message();
          msg.what=downloadOver;
          handler.sendMessage(msg);
        }
      }
      
    }
  }
}

以上这篇android多线程断点下载-带进度条和百分比进度显示效果就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。


# android多线程断点下载  # Android 下载文件通知栏显示进度条功能的实例代码  # Android编程实现显示在标题上的进度条功能【附源码下载】  # Android实现标题上显示隐藏进度条效果  # Android多线程+单线程+断点续传+进度条显示下载功能  # Android自定义多节点进度条显示的实现代码(附源码)  # Android使用AsyncTask下载图片并显示进度条功能  # Android 进度条显示在标题栏的实现方法  # Android上传文件到服务端并显示进度条  # Android实现支持进度条显示的短信备份工具类  # android实现动态显示隐藏进度条  # 进度条  # 多线程  # 临时文件  # 给大家  # 的是  # 希望能  # 请输入  # 这篇  # 数据库中  # 创建一个  # 小编  # 源代码  # 大家多多  # 计算出  # 是否存在  # 为空  # 进行下载  # 输入框  # 见底  # 显示效果 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: DeepSeek是免费使用的吗 DeepSeek收费模式与Pro版本功能详解  Laravel定时任务怎么设置_Laravel Crontab调度器配置  网站制作价目表怎么做,珍爱网婚介费用多少?  Laravel的辅助函数有哪些_Laravel常用Helpers函数提高开发效率  Laravel如何使用Laravel Vite编译前端_Laravel10以上版本前端静态资源管理【教程】  今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】  php读取心率传感器数据怎么弄_php获取max30100的心率值【指南】  太平洋网站制作公司,网络用语太平洋是什么意思?  Laravel怎么使用Markdown渲染文档_Laravel将Markdown内容转HTML页面展示【实战】  ChatGPT常用指令模板大全 新手快速上手的万能Prompt合集  黑客如何通过漏洞一步步攻陷网站服务器?  Win11怎么恢复误删照片_Win11数据恢复工具使用【推荐】  Python自然语言搜索引擎项目教程_倒排索引查询优化案例  javascript中闭包概念与用法深入理解  深圳网站制作培训,深圳哪些招聘网站比较好?  Laravel如何与Inertia.js和Vue/React构建现代单页应用  如何在IIS7中新建站点?详细步骤解析  装修招标网站设计制作流程,装修招标流程?  详解一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)  如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?  Laravel路由Route怎么设置_Laravel基础路由定义与参数传递规则【详解】  Windows11怎样设置电源计划_Windows11电源计划调整攻略【指南】  Laravel怎么调用外部API_Laravel Http Client客户端使用  惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?  Laravel如何记录日志_Laravel Logging系统配置与自定义日志通道  Laravel怎么使用Collection集合方法_Laravel数组操作高级函数pluck与map【手册】  智能起名网站制作软件有哪些,制作logo的软件?  如何打造高效商业网站?建站目的决定转化率  Windows10怎样连接蓝牙设备_Windows10蓝牙连接步骤【教程】  如何快速启动建站代理加盟业务?  EditPlus中的正则表达式 实战(2)  Laravel Docker环境搭建教程_Laravel Sail使用指南  制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?  Laravel如何优雅地处理服务层_在Laravel中使用Service层和Repository层  Laravel怎么解决跨域问题_Laravel配置CORS跨域访问  香港代理服务器配置指南:高匿IP选择、跨境加速与SEO优化技巧  Python数据仓库与ETL构建实战_Airflow调度流程详解  Edge浏览器提示“由你的组织管理”怎么解决_去除浏览器托管提示【修复】  Windows10如何更改计算机工作组_Win10系统属性修改Workgroup  5种Android数据存储方式汇总  如何在 Telegram Web View(iOS)中防止键盘遮挡底部输入框  详解jQuery中的事件  悟空识字怎么关闭自动续费_悟空识字取消会员自动扣费步骤  详解Nginx + Tomcat 反向代理 负载均衡 集群 部署指南  厦门模型网站设计制作公司,厦门航空飞机模型掉色怎么办?  Midjourney怎么调整光影效果_Midjourney光影调整方法【指南】  Laravel如何清理系统缓存命令_Laravel清除路由配置及视图缓存的方法【总结】  图片制作网站免费软件,有没有免费的网站或软件可以将图片批量转为A4大小的pdf?  Java垃圾回收器的方法和原理总结  如何在景安云服务器上绑定域名并配置虚拟主机?