当前位置: 移动技术网 > IT编程>移动开发>Android > Android编程开发实现带进度条和百分比的多线程下载

Android编程开发实现带进度条和百分比的多线程下载

2019年07月24日  | 移动技术网IT编程  | 我要评论

礼貌待人的俗语,郭潜,王中军父亲

本文实例讲述了android编程开发实现带进度条和百分比的多线程下载。分享给大家供大家参考,具体如下:

继上一篇《》之后,可以将它移植到我们的安卓中来,下面是具体实现源码:

downactivity.java:

package com.example.downloads;
import java.io.file;
import java.io.ioexception;
import java.io.randomaccessfile;
import java.net.httpurlconnection;
import java.net.malformedurlexception;
import java.net.url;
import com.example.downloads.utils.downloadthread;
import android.os.bundle;
import android.os.environment;
import android.os.handler;
import android.os.message;
import android.annotation.suppresslint;
import android.app.activity;
import android.text.textutils;
import android.view.menu;
import android.view.view;
import android.widget.edittext;
import android.widget.progressbar;
import android.widget.textview;
import android.widget.toast;
public class downactivity extends activity {
  // 声明控件
  // 路径与线程数量
  public edittext et_url, et_num;
  // 进度条
  public static progressbar pb_thread;
  // 显示进度的操作
  public textview tv_pb;
  // 线程的数量
  public static int threadnum = 3;
  // 每个线程负责下载的大小
  public int blocksize;
  public static int threadcount;// 数量
  // 访问的path
  public string path;
  public static boolean flag = true;
  // 记录进度条的值
  public static int pb_count = 0;
  public static handler handler;
  public static final int textvalue = 1;
  public static int pb_num = 0;
  public static int size = 0;
  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_down);
    et_url = (edittext) findviewbyid(r.id.et_path);
    et_num = (edittext) findviewbyid(r.id.et_threadnum);
    pb_thread = (progressbar) findviewbyid(r.id.pb_down);
    tv_pb = (textview) findviewbyid(r.id.tv_pb);
    handler = new handler() {
      @suppresslint("handlerleak")
      @override
      public void handlemessage(message msg) {
        super.handlemessage(msg);
        switch (msg.what) {
        case textvalue:
          system.out.println("-------" + downactivity.pb_count
              + "//////" + downactivity.size);
          // 改变textview
          pb_num = (downactivity.pb_count * 100) / downactivity.size;
          tv_pb.settext("当前进度是+" + pb_num + "%");
          break;
        default:
          break;
        }
      }
    };
  }
  @override
  public boolean oncreateoptionsmenu(menu menu) {
    // inflate the menu; this adds items to the action bar if it is present.
    getmenuinflater().inflate(r.menu.main, menu);
    return true;
  }
  public void download(view v) {
    downactivity.flag = true;
    downactivity.pb_count = 0;
    path = et_url.gettext().tostring();
    string threadnum_et = et_num.gettext().tostring();
    if (textutils.isempty(path) || textutils.isempty(threadnum_et)) {
      toast.maketext(this, "不能为空", toast.length_long).show();
      return;
    }
    toast.maketext(this, "url:" + path + "--" + threadnum_et,
        toast.length_long).show();
    // 转换成数字
    threadnum = integer.valueof(threadnum_et);
    new thread(new runnable() {
      @override
      public void run() {
        try {
          // 创建出url对象
          url url = new url(path);
          // 创建出 httpurlconnection对象
          httpurlconnection httpurlconnection = (httpurlconnection) url
              .openconnection();
          // 设置 发请求发送的方式
          httpurlconnection.setrequestmethod("get");
          // 设置请求是否超时时间
          httpurlconnection.setconnecttimeout(5000);
          // 设置
          httpurlconnection
              .setrequestproperty("user-agent",
                  " mozilla/5.0 (compatible; msie 10.0; windows nt 6.2; trident/6.0)");
          // 是否响应成功
          if (httpurlconnection.getresponsecode() == 200) {
            // 获取文件的大小
            size = httpurlconnection.getcontentlength();
            system.out.println("文件的大小" + size);
            // 设置进度条的最大值
            pb_thread.setmax(size);
            // 创建文件 //保存到sd卡上
            // 首先判断是否拥有sdcard
            if (environment.getexternalstoragestate().equals(
                environment.media_mounted)) {
              // 获取sdcard文件目录对象
              file sdfile = environment
                  .getexternalstoragedirectory();
              // 创建文件对象
              file file = new file(sdfile, "youdao.exe");
              randomaccessfile accessfile = new randomaccessfile(
                  file, "rwd");
              // 设置文件的大小
              accessfile.setlength(size);
              // 每个线程下载的大小
              blocksize = size / threadnum;
              // 开三个线程 操作此文件
              for (int i = 1; i <= threadnum; i++) {
                // 1 2 3
                // 计算出每个线程开始的位置
                int startsize = (i - 1) * blocksize;
                // 结束位置
                int endsize = (i) * blocksize;
                // 当线程是最后一个线程的时候
                if (i == threadnum) {
                  // 判断文件的大小是否大于计算出来的结束位置
                  if (size > endsize) {
                    // 结束位置 等于 文件的大小
                    endsize = size;
                  }
                }
                // 为每个线程创建一个随机的读取
                randomaccessfile threadaccessfile = new randomaccessfile(
                    file, "rwd");
                new thread(new downloadthread(i,
                    threadaccessfile, startsize, endsize,
                    path)).start();
              }
            }
          }
        } catch (malformedurlexception e) {
          e.printstacktrace();
        } catch (ioexception e) {
          e.printstacktrace();
        }
      }
    }).start();
  }
  /**
   * 暂停操作
   *
   * @param v
   */
  public void downpause(view v) {
    toast.maketext(this, "暂停", toast.length_long).show();
    this.flag = false;
  }
}

downloadthread.java:

package com.example.downloads.utils;
import java.io.file;
import java.io.fileinputstream;
import java.io.fileoutputstream;
import java.io.ioexception;
import java.io.inputstream;
import java.io.randomaccessfile;
import java.net.httpurlconnection;
import java.net.malformedurlexception;
import java.net.url;
import com.example.downloads.downactivity;
import android.os.environment;
public class downloadthread implements runnable {
  public randomaccessfile accessfile; // 每个线程 都拥有一个accessfile的文件对象 线程1 线程2 线程3
  // 线程下载文件的起始位置
  public int startsize;
  public int endsize;
  // 文件下载的path路径
  public string path;
  public int threadid; // 线程的标识
  public downloadthread(int threadid, randomaccessfile accessfile,
      int startsize, int endsize, string path) {
    this.threadid = threadid;
    this.accessfile = accessfile;
    this.startsize = startsize;
    this.endsize = endsize;
    this.path = path;
  }
  @override
  public void run() {
    // 执行run方法
    try {
      // 创建文件到sd卡上去
      // 首先判断是否拥有sdcard
      if (environment.getexternalstoragestate().equals(
          environment.media_mounted)) {
        // 获取sdcard文件目录对象
        file sdfile = environment.getexternalstoragedirectory();
        file threadfile = new file(sdfile, threadid + ".txt");
        if (threadfile.exists()) {
          // 读取该文件的内容
          // 创建文件的输入流对象
          fileinputstream fis = new fileinputstream(threadfile);
          // 采用工具类读取
          byte data[] = streamtools.istodata(fis);
          // 转化成字符串
          string threadlen = new string(data);
          if ((threadlen != null) && (!"".equals(threadlen))) {
            startsize = integer.valueof(threadlen);
            // 解决 416bug的错误
            if (startsize > endsize) {
              startsize = endsize - 1;
            }
          }
        }
        // 创建文件
        // 创建url对象
        url url = new url(path);
        // 创建httpurlconnection对象
        httpurlconnection httpurlconnection = (httpurlconnection) url
            .openconnection();
        // 设置请求的头
        httpurlconnection.setrequestmethod("get");
        // 设置请求是否超时时间
        httpurlconnection.setconnecttimeout(5000);
        // 设置
        httpurlconnection
            .setrequestproperty("user-agent",
                " mozilla/5.0 (compatible; msie 10.0; windows nt 6.2; trident/6.0)");
        // 关键的设置
        httpurlconnection.setrequestproperty("range", "bytes="
            + startsize + "-" + endsize);
        // 输出当前线程
        system.out.println("当前线程" + threadid + " 下载开始位置:" + startsize
            + " 下载结束位置:" + endsize);
        // 响应成功
        // 设置随机读取文件的 开始位置
        accessfile.seek(startsize);
        // 获取相应流对象
        inputstream is = httpurlconnection.getinputstream();
        // 创建输出流对象
        byte buffer[] = new byte[1024];
        int len = 0;
        int threadtotal = 0;// 每个线程下载后保存记录 /
        while ((len = is.read(buffer)) != -1) {
          accessfile.write(buffer, 0, len);
          threadtotal += len;// 记录你写入的长度 //xml文件
          //改变进度条:
          setprogressbar(len);
          // 通过文件记录文件下载的长度
          fileoutputstream fos = new fileoutputstream(threadfile);
          fos.write((threadtotal + "").getbytes());
          fos.flush();
          fos.close();
          //发送handler消息
          downactivity.handler.sendemptymessage(downactivity.textvalue);
          if(!downactivity.flag){
            return;
          }
        }
        accessfile.close();
        is.close();
        system.out.println(threadid + "线程执行完毕");
        // 线程操作
        synchronized (downactivity.class) {
          downactivity.threadcount++;
          if (downactivity.threadcount >= downactivity.threadnum) {
            for (int i = 1; i <= downactivity.threadnum; i++) {
              // 获取sdcard上的文件
              file deletefile = new file(sdfile, i + ".txt");
              if (deletefile.exists()) {
                // 文件删除
                deletefile.delete();
              }
            }
          }
        }
      }
    } catch (malformedurlexception e) {
      // todo auto-generated catch block
      e.printstacktrace();
    } catch (ioexception e) {
      // todo auto-generated catch block
      e.printstacktrace();
    }
  }
  public synchronized void setprogressbar(int len){
    downactivity.pb_count+=len;
    downactivity.pb_thread.setprogress(downactivity.pb_count);
  }
}

streamtools.java:

package com.example.downloads.utils;
import java.io.bytearrayoutputstream;
import java.io.ioexception;
import java.io.inputstream;
public class streamtools {
  public static byte[] istodata(inputstream is) throws ioexception{
    // 字节输出流
    bytearrayoutputstream bops = new bytearrayoutputstream();
    // 读取数据的缓存区
    byte buffer[] = new byte[1024];
    // 读取长度的记录
    int len = 0;
    // 循环读取
    while ((len = is.read(buffer)) != -1) {
      bops.write(buffer, 0, len);
    }
    // 把读取的内容转换成byte数组
    byte data[] = bops.tobytearray();
    bops.flush();
    bops.close();
    is.close();
    return data;
  }
}

strings.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string name="app_name">downloads</string>
  <string name="action_settings">settings</string>
  <string name="tv_down">文件下载的地址</string>
  <string name="tv_threadnum">线程数量</string>
  <string name="tv_num">0%</string>
  <string name="btn_text">下载</string>
  <string name="btn_pause">暂停</string>
  <string name="et_path">http://172.22.64.8:8080/doudou/youdao.exe</string>
  <string name="et_threadnum">3</string>
</resources>

布局文件:

<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingbottom="@dimen/activity_vertical_margin"
  android:paddingleft="@dimen/activity_horizontal_margin"
  android:paddingright="@dimen/activity_horizontal_margin"
  android:paddingtop="@dimen/activity_vertical_margin"
  tools:context=".downactivity" >
  <textview
    android:id="@+id/textview1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignparentleft="true"
    android:layout_alignparenttop="true"
    android:text="@string/tv_down" />
  <edittext
    android:id="@+id/et_path"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignparentleft="true"
    android:layout_alignparentright="true"
    android:layout_below="@+id/textview1"
    android:ems="10"
    android:inputtype="none"
    android:text="@string/et_path" >
    <requestfocus />
  </edittext>
  <textview
    android:id="@+id/textview2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignparentleft="true"
    android:layout_below="@+id/et_path"
    android:text="@string/tv_threadnum" />
  <edittext
    android:id="@+id/et_threadnum"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignleft="@+id/textview2"
    android:layout_alignright="@+id/et_path"
    android:layout_below="@+id/textview2"
    android:ems="10"
    android:inputtype="number"
    android:text="@string/et_threadnum" />
  <progressbar
    android:id="@+id/pb_down"
    style="?android:attr/progressbarstylehorizontal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignleft="@+id/et_threadnum"
    android:layout_alignright="@+id/et_threadnum"
    android:layout_below="@+id/et_threadnum"
    android:layout_margintop="14dp" />
  <textview
    android:id="@+id/tv_pb"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignright="@+id/textview1"
    android:layout_below="@+id/pb_down"
    android:layout_margintop="24dp"
    android:text="@string/tv_num" />
  <button
    android:id="@+id/btn_down"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignleft="@+id/pb_down"
    android:layout_below="@+id/tv_pb"
    android:layout_margintop="32dp"
    android:onclick="download"
    android:text="@string/btn_text" />
  <button
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignleft="@+id/btn_down"
    android:layout_below="@+id/btn_down"
    android:layout_margintop="16dp"
    android:onclick="downpause"
    android:text="@string/btn_pause" />
</relativelayout>

效果如下:

最后要注意的是别忘了在项目清单文件中加入权限:

<!-- sdcard权限 -->
<uses-permission android:name="android.permission.mount_unmount_filesystems" />
<uses-permission android:name="android.permission.write_external_storage" />
<!-- 访问网络的权限 -->
<uses-permission android:name="android.permission.internet" />

希望本文所述对大家android程序设计有所帮助。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网