安卓多线程下载

package com.example.day11_download;

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.day11_download.util.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.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class DownActivity extends Activity {
 // 声明控件
 // 路径与线程数量
 private EditText et_url, et_num;
 // 进度条
 public static ProgressBar pb_thread;
 // 显示进度的操作
 private 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_main);

  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) {

  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() {
   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");

       @SuppressWarnings("resource")
       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) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }

   }
  }).start();

 }

 /**
  * 暂停
  */

 public void downPause(View v) {
  Toast.makeText(this, "暂停", Toast.LENGTH_LONG).show();
  DownActivity.flag = false;
 }
}

-----------------------------------------------------------------------------------------------------------------------------------------------

package com.example.day11_download.util;


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 android.os.Environment;

import com.example.day11_download.DownActivity;

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);
 }
 
 
 
}

==================================================================================

package com.example.day11_download.util;


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;
 }
}

------------------------------------------------------------------------------------------------------------------------------------

界面设置

<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:background="@drawable/back"
    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:text="@string/et_path"
        android:inputType="text">

        <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" />

    <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_alignBaseline="@+id/btn_down"
        android:layout_alignBottom="@+id/btn_down"
        android:layout_alignRight="@+id/pb_down"
        android:layout_marginRight="38dp"
        android:onClick="downPause"
        android:text="@string/btn_pause" />

    <TextView
        android:id="@+id/tv_pb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/pb_down"
        android:layout_marginTop="26dp"
        android:layout_toRightOf="@+id/textView2"
        android:text="@string/tv_num" />

</RelativeLayout>

====================================================================

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">多线程下载</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</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.10:8080/doudou/youdao.exe</string>
    <string name="et_threadNum">3</string>

</resources>

==================================================================================

设置权限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.day11_download"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
    <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"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.day11_download.DownActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值