文章来源:http://www.itnose.net/detail/6051823.html
更多文章:http://www.itnose.net/type/85.html
本应用实现的是输入文件的网络的地址,点击按钮开始下载,下载过程中有进度条和后面的文本提示进度,
下载过程中按钮不可点击,防止重复的下载,下载完毕后会进行Toast的提示显示,
并且回复按钮的可点击性,进度条也会清空,当然如果下载中途结束应用进程就会进行进度的保存,
下次下载同样的文件时就会从进度记录进行下载,节省流量和时间
应用需要的应用权限:
访问网络权限
<uses-permission android:name="android.permission.INTERNET"/>
外部储存的写入权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
布局文件代码
<LinearLayout 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:orientation="vertical" tools:context=".MainActivity" > <EditText android:id="@+id/et_path" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" android:hint="请输入下载文件的地址" android:singleLine="true" android:text="http://172.22.64.193:8080/test.exe" > </EditText> <TableLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <TableRow android:layout_width="match_parent" android:layout_height="wrap_content" > <ProgressBar android:id="@+id/pb" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="8" /> <TextView android:id="@+id/tv_progressNumber" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="2" android:gravity="center" android:text="0%" /> </TableRow> </TableLayout> <Button android:id="@+id/bt_startDownlode" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="startDownlode" android:text="开始下载" /> </LinearLayout>
核心代码
package com.examp.mutildownloader; 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.Environment; import android.os.Handler; import android.os.Message; import android.text.TextUtils; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; /** * Android下的多线程下载,断点下载 * * @author MartinDong * */ public class MainActivity extends Activity { // sd卡的路径 private static final File sd = Environment.getExternalStorageDirectory(); private static final int DOWNLODE_ERROR = 1; private static final int DOWNLODE_SUCCESS = 2; private static final int DOWNLODE_DELETE_TEMP = 3; public static final int PROGRESS_NUMBER_CHANGE = 4; // 定义线程个数 private static int threadCount = 3; // 定义当前存货的线程个数 private static int runningThread = 3; // 组件的获取 private EditText et_path; private ProgressBar pb; private Button bt_startDownlode; private TextView tv_progressNumber; // 定义存储的文件名称 private String filename; // 设置进度条的进度 // 进度条的数据 public int progressTemp = 0; // 定义消息处理 private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case DOWNLODE_ERROR: Toast.makeText(getApplicationContext(), "下载失败....", Toast.LENGTH_SHORT).show(); break; case DOWNLODE_SUCCESS: // 设置按钮可用 bt_startDownlode.setEnabled(true); // 清空进度 progressTemp = 0; pb.setProgress(progressTemp); // 文本清0 tv_progressNumber.setText("0%"); Toast.makeText(getApplicationContext(), "下载成功....", Toast.LENGTH_SHORT).show(); break; case DOWNLODE_DELETE_TEMP: Toast.makeText(getApplicationContext(), "删除进度文件....", Toast.LENGTH_SHORT).show(); break; case PROGRESS_NUMBER_CHANGE: tv_progressNumber.setText(pb.getProgress() * 100 / pb.getMax() + "%"); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_path = (EditText) findViewById(R.id.et_path); // 获取组件 pb = (ProgressBar) findViewById(R.id.pb); bt_startDownlode = (Button) findViewById(R.id.bt_startDownlode); tv_progressNumber = (TextView) findViewById(R.id.tv_progressNumber); } public void startDownlode(View view) { // 设置按钮不可点击//防止重复提交 bt_startDownlode.setEnabled(false); // 从控件中获取下载的路径 final String path = et_path.getText().toString().trim(); // 获取输入地址的最后一个"/"出现的位置 int lastIndex = path.lastIndexOf("/"); // 获取文件名称及格式 filename = path.substring(lastIndex + 1, path.length()); System.out.println("文件名称为===============" + filename); // 判断路径是否有效 if (TextUtils.isEmpty(path)) { Toast.makeText(this, "请输入有效的下载路径......", Toast.LENGTH_SHORT).show(); return; } // 为了避免与主线程冲突,开启子线程完成,避免anr问题 new Thread() { public void run() { try { // 1,连接到服务器,获取一个文件,获取文件的大小跟服务器的文件一样的临时文件 // String path = "http://172.22.64.193:8080/tomcat.css"; 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); System.out.println("文件总长度:" + length); // 在客户端创建出一个跟服务器大小一致的临时文件 RandomAccessFile raf = new RandomAccessFile(sd + "/" + filename, "rwd"); // 指定临时文件的大小 raf.setLength(length); // 释放资源 raf.close(); // 平均每一个线程的文件大小 int blockSize = length / threadCount; // 设置活跃的线程 runningThread = threadCount; for (int threadId = 1; threadId <= threadCount; threadId++) { // 线程开始的下载位置 int startIndex = (threadId - 1) * blockSize; // 线程的结束位置 int endIndex = threadId * blockSize - 1; // 判断是否是最后一个线程 if (threadId == threadCount) { // 设置结束的位置为到文件的最后 endIndex = length; } System.out.println("线程:" + threadId + "下载:开始位置>>>>>>>>" + startIndex + "结束>>>>>>>>>>" + endIndex); new DownlodeThread(path, threadId, startIndex, endIndex).start(); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }; }.start(); } /** * 下载文件的子线程类,每一个线程下载对应位置文件数据 * * @author MartinDong * */ public class DownlodeThread extends Thread { private String path; private int threadId; private int startIndex; private int endIndex; /** * * @param path * 文件的下载路径 * @param threadId * 线程id * @param startIndex * 线程开始的位置 * @param endIndex * 线程结束的位置 */ public DownlodeThread(String path, int threadId, int startIndex, int endIndex) { this.path = path; this.threadId = threadId; this.startIndex = startIndex; this.endIndex = endIndex; } @Override public void run() { try { // 检查是否存在下载历史的文件 File tempFile = new File(sd + "/" + threadId + ".txt");// =========================断点记录操作=============================== if (tempFile.exists() && tempFile.length() > 0) { // 文件输入流 FileInputStream fis = new FileInputStream(tempFile); // 中间变量,缓存的作用 byte[] tempBuffer = new byte[1024]; // 获取进度文件的数据大小 int length = fis.read(tempBuffer); // 获取进度文件的数据 String historyData = new String(tempBuffer, 0, length); // 将进度数据装换为整型 int historyDataInt = Integer.parseInt(historyData); // 如果是断点传送,初始化进度条的进度 // 获取每个线程已经下载了的进度 int temp = historyDataInt - startIndex; // 为进度重新赋值 progressTemp += temp; // 修改真正的下载位置 startIndex = historyDataInt; fis.close(); }// =========================断点记录操作=============================== // 将地址转换为URL URL url = new URL(path); // 获取http连接 HttpURLConnection conn = (HttpURLConnection) url .openConnection(); // 设置连接的请求方式 conn.setRequestMethod("GET"); // 重要:请求服务器下载部分的文件,指定文件的位置 conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); System.out .println("线程:" + threadId + "真实开始的下载进度:" + startIndex); // 设置超时时间 conn.setReadTimeout(5000); // 得到服务器的状态码,200表示请求的全部资源得到响应=== ok,206请求的部分资源得到响应=== ok int code = conn.getResponseCode(); System.out.println("code:" + code); if (code == 206) { // 返回的是指定位置的文件流 InputStream is = conn.getInputStream(); // 创建一个临时的文件 RandomAccessFile raf = new RandomAccessFile(sd + "/" + filename, "rwd"); // 移动指针,到指定的文件位置, raf.seek(startIndex); // 创建中间缓冲字节数组 byte[] buffer = new byte[1024]; // 读取文件的大小 int length = 0; // 定义已经下载的数据长度,用作断点下载的记录=========================断点记录操作=============================== int downlodeTotal = 0; // 循环写入 while ((length = is.read(buffer)) != -1) { // 定义一个记录线程的记录文件=========================断点记录操作=============================== RandomAccessFile historyFile = new RandomAccessFile(sd + "/" + threadId + ".txt", "rwd"); // 向文件中写入数据 raf.write(buffer, 0, length); // 记录已经下载的文件长度 downlodeTotal += length; // 将已经下载的文件长度和开始的读取位置相加,得到已经读取的文件位置 historyFile.write((downlodeTotal + startIndex + "") .getBytes()); historyFile.close();// =========================断点记录操作=============================== // 保持同步的更新 synchronized (MainActivity.this) { // 将每个线程的读取文件的大小累加到下载进度上 progressTemp += length; // 更新界面上的Progress的进度条的长度 pb.setProgress(progressTemp); // 特殊情况ProgressBar ProgressDialog // 是可以直接在子线程中跟新ui的,内部代码有过特殊的处理 Message msg = new Message(); msg.what = PROGRESS_NUMBER_CHANGE; handler.sendMessage(msg); } } is.close(); raf.close(); System.out.println("线程:" + threadId + "下载完毕............"); } else { System.out.println("线程:" + threadId + "下载失败请重新下载............"); // 向消息处理器发送信息 Message msg = new Message(); msg.what = DOWNLODE_ERROR; handler.sendMessage(msg); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { synchronized (MainActivity.this) { // 进行线程数量的变化操作 runningThread--; // 如果当前存活的线程为0,执行进度文件统一销毁的操作 if (runningThread == 0) { // 如果下载完毕,清除进度文件 for (int threadIndex = 1; threadIndex <= threadCount; threadIndex++) { // 这里创建的是与线程文件对应的文件,文件名可以自定义,方便起见是采用的是线程的ID表示 File temp = new File(sd + "/" + threadIndex + ".txt"); // 执行文件删除的操作 temp.delete(); } System.out.println("下载完毕,删除进度文件............."); // 向消息处理器发送信息 // 向消息处理器发送信息 Message msg = new Message(); msg.what = DOWNLODE_SUCCESS; handler.sendMessage(msg); } } } } } }
文章来源:http://www.itnose.net/detail/6051823.html
更多文章:http://www.itnose.net/type/85.html
相关推荐
Android多线程断点续传下载器,很好的学习资料,包括完整代码以及详细注释。 无须其他配置,在网上找一个mp3下载地址(我找的是百度音乐)放到strings.xml不报错就行。
摘要:Java源码,Android源码,多线程下载 Java源码,android多线程下载器演示,内含APK文件,已经生成了可在Android上运行的APK文件,多线程下载在Android中使用很普遍,是一项值得掌握的Android编程技术。...
android客户端多线程下载文件的一个demo,涉及到SQLite的简单应用,希望能够帮到初学者。
Android 多线程可断点续传上传文件至服务器Demo(Android端编辑器:Android Studio,服务器端编辑器:Eclipse,请注意手机默认下载目录必须要有t007.zip,服务器端必须有D:\temp\temp目录)
Android环境下多线程文件下载器的设计.pdf
android多线程断点下载,通过本Android下载实例,可了解到以下知识技巧:实时得到文件下载的长度,设置获取实体数据的范围、获取文件已下载文件长度、原始文件长度、线程数、本地保存文件、缓存各线程下载的长度、每...
android多线程下载器.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
在上一篇博文《Android多线程下载示例》中,我们讲解了如何实现Android的多线程下载功能,通过将整个文件分成多个数据块,开启多个线程,让每个线程分别下载一个相应的数据块来实现多线程下载的功能。多线程下载中,...
采用多个线程下载文件等。利用多线程的下载原理,实现了一个简单的android应用程序下载文件。
Android多线程断点续传下载器,很好的学习资料,包括完整代码以及详细注释。 无须其他配置,服务器端只需建立一个Dynamic project,然后包含一个mp3文件即可。
本资源为网页多线程下载器各个版本的安装包,主要包含6.36.2(俄罗斯大神修改版)和6.27这两个版本。该下载器可搭配谷歌浏览器使用,可以多线程下载网页上的所有格式文件,速度非常快,用起来超级方便,欢迎下载!
代码可接运行,也可以直接用手机安装里面的apk文件,多个文件下载时,刷新UI并且滑动listView,不会有卡顿问题.
Android文件管理器(增加了文件夹复制移动,下载资源暂停删除等,以及复制过程中的可视化进程)是一个基于Android开发的应用,包含常用文件操作以及文件下载功能,文件操作包括打开文件夹和打开各类的文件(apk、avi...
Android多线程断点续传下载器,很好的学习资料,包括完整代码以及详细注释。 无须其他配置,服务器端只需建立一个Dynamic project,然后包含一个mp3文件即可.rar,太多无法一一验证是否可用,程序如果跑不起来需要自...
Android多线程断点续传下载器,很好的学习资料,包括完整代码以及详细注释。 无须其他配置,服务器端只需建立一个Dynamic project,然后包含一个mp3文件即可
本项目完成的功能类似与迅雷等下载工具所实现的功能——实现多线程断点下载。 主要设计的技术有: 1、android中主线程与非主线程通信机制。 2、多线程的编程和管理。 3、android网络编程 4、自己设计实现设计...
下面,我们一起来实现一个Android中利用多线程下载文件的小例子。 二、服务端准备 在这个小例子中我以下载有道词典为例,在网上下载有道词典的安装包,在eclipse中新建项目web,将下载的有道词典安装包放置在...
主要介绍了Android编程开发实现多线程断点续传下载器,涉及Android多线程,文件传输及断点续传的相关技巧,需要的朋友可以参考下
Android文件管理器是一个基于Android开发的应用,包含常用文件操作以及文件下载功能,文件操作包括打开文件夹和打开各类的文件(apk、avi、mp3、doc等等),以及文件的移动,文件夹的创建,文件/文件夹大小查看,...