在这一节中,我们就来讲多线程下载以及断点续传在android中怎么使用,前两节是为本节做准备的,没有看前两节的同学,最好看完前面的两篇文章再来看这篇。其实在android端的应用和java基本上是差不多的,只不过在android端我建议对于断点续传的记录的保存放在android的sqlite3的数据库中,这样是最好的,当然保存在sd卡中也行,我为了方便起见,我没有建立数据库,而是直接保存到了sd卡中。先看一下我在android中运行的效果图,如下:

我在这里的代码加上了进度条的显示和下载进度百分比的显示,为了让进度条和百分比不混乱,我为下载线程中计算下载进度的代码加上了锁。如下:

还有就是下边的一段代码我把记录下载进度的文件保存到了SD卡中,我建议最好用数据库。这段代码如下:

其它的我倒是没有什么好解释的了,跟上一篇文章的内容差不多,而且我在代码中已经写得很详细了,那么就请大家看代码吧!

MainActivity中的代码如下:

package net.loonggg.android.downloader;

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.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast; @SuppressLint("HandlerLeak")
public class MainActivity extends Activity {
public int currentProcess = 0;// 下载文件的当前进度
// 开启的线程的个数
public static final int THREAD_COUNT = 3;
public static int runningThread = 3;// 记录正在运行的下载文件的线程数
private EditText et;
private Button btn;
private TextView tv;
private ProgressBar pb;// 下载进度条 private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.arg1) {
case 0:
Toast.makeText(getApplicationContext(), "下载失败!",
Toast.LENGTH_SHORT).show();
break;
case 1:
Toast.makeText(getApplicationContext(), "下载完成!",
Toast.LENGTH_SHORT).show();
break;
case 2:
tv.setText("下载进度:" + pb.getProgress() * 100 / pb.getMax() + "%");
break;
default:
break;
}
};
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
et = (EditText) findViewById(R.id.et);
pb = (ProgressBar) findViewById(R.id.pb);
btn = (Button) findViewById(R.id.btn);
tv = (TextView) findViewById(R.id.tv_process);
btn.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
downLoad();
}
});
} /**
* 下载文件的方法
*/
private void downLoad() {
final String path = et.getText().toString();
new Thread() {
public void run() {
try {
// 1、连接服务器,获取一个文件,获取文件的长度,在本地创建一个大小跟服务器文件大小一样的临时文件
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(
"/sdcard/temp.apk", "rwd");
// 指定创建的这个文件的长度
raf.setLength(length);
// 关闭raf
raf.close();
// 假设是3个线程去下载资源
// 平均每一个线程下载的文件的大小
int blockSize = length / THREAD_COUNT;
for (int threadId = 1; threadId <= THREAD_COUNT; threadId++) {
// 第一个线程开始下载的位置
int startIndex = (threadId - 1) * blockSize;
int endIndex = threadId * blockSize - 1;
if (threadId == THREAD_COUNT) {
endIndex = length;
}
System.out.println("----threadId---"
+ "--startIndex--" + startIndex
+ "--endIndex--" + endIndex);
new DownloadThread(path, threadId, startIndex,
endIndex).start();
}
}
} catch (Exception e) {
e.printStackTrace();
Message msg = new Message();
msg.arg1 = 0;
handler.sendMessage(msg);
}
};
}.start();
} /**
* 下载文件的子线程,每一个线程下载对应位置的文件
*
* @author loonggg
*
*/
public class DownloadThread extends Thread {
private int threadId;
private int startIndex;
private int endIndex;
private String path; /**
* @param path
* 下载文件在服务器上的路径
* @param threadId
* 线程id
* @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() {
try {
// 检查是否存在记录下载长度的文件,如果存在读取这个文件的数据
// -------------------------替换成数据库----------------------------
File tempFile = new File("/sdcard/" + threadId + ".txt");
if (tempFile.exists() && tempFile.length() > 0) {
FileInputStream fis = new FileInputStream(tempFile);
byte[] temp = new byte[1024 * 10];
int leng = fis.read(temp);
// 已经下载的长度
String downloadLen = new String(temp, 0, leng);
int downloadInt = Integer.parseInt(downloadLen);
// ------------------这两行代码是关于断点续传时,设置进度条的起点时的关键代码-------------------
int alreadyDownloadInt = downloadInt - startIndex;
currentProcess += alreadyDownloadInt;// 计算每个线程上次断点已经下载的文件的长度
// ---------------------------------------------------------------------------------
startIndex = downloadInt;
fis.close();
}
// --------------------------------------------------------------- URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setRequestMethod("GET");
// 重要:请求服务器下载部分的文件 指定文件的位置
conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
+ endIndex);
conn.setConnectTimeout(5000);
// 从服务器请求全部资源的状态码200 ok 如果从服务器请求部分资源的状态码206 ok
int code = conn.getResponseCode();
System.out.println("---code---" + code);
InputStream is = conn.getInputStream();// 已经设置了请求的位置,返回的是当前位置对应的文件的输入流
RandomAccessFile raf = new RandomAccessFile("/sdcard/temp.apk",
"rwd");
// 随机写文件的时候从哪个位置开始写
raf.seek(startIndex);// 定位文件
int len = 0;
byte[] buffer = new byte[1024];
int total = 0;// 记录已经下载的数据的长度
while ((len = is.read(buffer)) != -1) {
RandomAccessFile recordFile = new RandomAccessFile(
"/sdcard/" + threadId + ".txt", "rwd");// 记录每个线程的下载进度,为断点续传做标记
raf.write(buffer, 0, len);
total += len;
recordFile.write(String.valueOf(startIndex + total)
.getBytes());
recordFile.close();
// 同步加锁,防止混乱
synchronized (MainActivity.this) {
currentProcess += len;// 获取当前的总进度
// 特殊情况,ProgressBarH和ProgressDialog进度条和对话框可以在子线程里面更新UI,系统内部代码特殊处理
pb.setProgress(currentProcess);// 更改界面上进度条的进度
Message msg = Message.obtain();
msg.arg1 = 2;
// 发送更新消息,更新进度的百分比
handler.sendMessage(msg);
}
}
is.close();
raf.close();
System.out.println("线程:" + threadId + "下载完毕了!");
} catch (Exception e) {
e.printStackTrace();
Message msg = handler.obtainMessage();
msg.arg1 = 0;
handler.sendMessage(msg);
} finally {
threadFinish();
}
} /**
* 我个人认为不锁定也可以,但是锁定可能更安全,如果谁有好的建议,到底用不用锁定,请给我留言
*/
private synchronized void threadFinish() {
runningThread--;
if (runningThread == 0) {// 所有的线程已经执行完毕
for (int i = 1; i <= THREAD_COUNT; i++) {// 删除记录下载进度的文件
File file = new File("/sdcard/" + i + ".txt");
file.delete();
Message msg = handler.obtainMessage();
msg.arg1 = 1;
handler.sendMessage(msg);
}
}
}
} }

还有就是对应的Activity_main.xml的代码如下:

<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" > <EditText
android:id="@+id/et"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="http://dl1.byme001.com/phone_android.apk" /> <ProgressBar
android:id="@+id/pb"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content" /> <TextView
android:id="@+id/tv_process"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下载进度"
android:textSize="30sp" /> <Button
android:id="@+id/btn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="下载" /> </LinearLayout>

当然大家别忘了在清单文件中设置网络权限和读写SD卡的权限:

 <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

到这里就完了!大家如果有什么不明白的,可以在下面留言!

转载请注明出处:http://blog.csdn.net/loongggdroid/article/details/17846085

Android学习记录(6)—将java中的多线程下载移植到Android中(即多线程下载在Android中的使用)③的更多相关文章

  1. Android学习记录(3)—Android中ContentProvider的基本原理学习总结

    一.ContentProvider简介        当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据.虽然使用其他方法也可以对外共享数据 ...

  2. 四、Android学习第四天——JAVA基础回顾(转)

    (转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 四.Android学习第四天——JAVA基础回顾 这才学习Android的 ...

  3. Android学习记录(5)—在java中学习多线程下载之断点续传②

    在上一节中我们学习了在java中学习多线程下载的基本原理和基本用法,我们并没有讲多线程的断点续传,那么这一节我们就接着上一节来讲断点续传,断点续传的重要性不言而喻,可以不用重复下载,也可以节省时间,实 ...

  4. Android学习记录(4)—在java中学习多线程下载的基本原理和基本用法①

    多线程下载在我们生活中非常常见,比如迅雷就是我们常用的多线程的下载工具,当然还有断点续传,断点续传我们在下一节来讲,android手机端下载文件时也可以用多线程下载,我们这里是在java中写一个测试, ...

  5. Android学习记录:SQLite数据库、res中raw的文件调用

    SQLite数据库是一种轻量级的关系型数据库. 在android中保存数据或调用数据库可以利用SQLite. android中提供了几个类来管理SQLite数据库 SQLiteDatabass类用来对 ...

  6. mono for android 学习记录

    C#开发Android应用实战(全 扫描 中文版) 学习记录: 拖完控件后,不要急着按F5,需要重新生成,才能自动修改 Resource.Designer.cs 文件 1. Activity 是基于a ...

  7. android 学习记录-----------android 活动 意图 碎片

    将此篇博客作为记录android项目开发过程中的学习记录

  8. Android学习记录(二)——第一次hello world及遇到的gradle安装问题

    开始一个简单的hello world项目,简单了解Android studio的使用方法 第一步,打开Android studio,点击Create New Project 第二步,选择需要的模板 T ...

  9. Android学习记录:界面设计

    本片文章将记录进行android界面开发时积累的知识 包括 activity全屏 activity跳转 button设计 逐个输入编辑框设计 d0710 合并旧文章总结更新 d0721 添加内容 == ...

随机推荐

  1. 梦织未来Windows驱动编程 第03课 驱动的编程规范

    最近根据梦织未来论坛的驱动教程学习了一下Windows下的驱动编程,做个笔记备忘.这是第03课<驱动的编程规范>. 驱动部分包括基本的驱动卸载函数.驱动打开关闭读取写入操作最简单的分发例程 ...

  2. window下mycat要放在根目录下

    原理文档没有跟我开玩笑呢? 建议放在盘符根目录下 ,无视的我,检查了多遍jdk环境,检查了多遍bat文件内容,仍然没有解决 找不到或无法加载主类 直到我乖乖的把目录放跟盘符才解决,心好累= =! 可能 ...

  3. MySQL数据库实验四:嵌套查询

    实验四          嵌套查询 一.实验目的 掌握SELECT语句的嵌套使用,实现表的复杂查询,进一步理解SELECT语句的高级使用方法. 二.实验环境 三.实验示例 1.  查询与“刘晨”在同一 ...

  4. Java访问重定向接口

    背景:开发做了一个免登陆的接口,方便我后续给管理后台做一些小工具,问题来了,给的免登陆接口是个302如图的test_login,在重定向一个200的接口(eload_admin), 原本开始这样做:0 ...

  5. A. Round House_数学问题

    A. Round House time limit per test 1 second memory limit per test 256 megabytes input standard input ...

  6. Java 压缩文件夹工具类(包含解压)

    依赖jar <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons ...

  7. linux中CURL的安装

    curl是一款著名的字符界面下的下载工具,支持HTTP.HTTPS.FTP.FTPS.DICT.TELNET.LDAP.FILE,和GOPHER.此外还具有cookies支持.断点续传.FTP上传.密 ...

  8. IIS无法识别的属性targetFramework

    出现这种错误是因为发布网站时iis的应用程序池默认使用的是.net framework v2.0.50727.4927,而开发的网站用的是.net framework 4.5,所以会出现这种错误. 我 ...

  9. System.Web

    如果 using System.Web:还是调用不出来其中的类,请在引用的位子添加 System.Web  引用,有的版本不自带这个命名空间. 类: HttpResponse类       用于绘画验 ...

  10. .Net Core爬虫爬取妹子网图片

    现在网上大把的Python的爬虫教程,很少看见有用C#写的,正好新出的.Net Core可以很方便的部署到Linux上,就用妹子图做示范写个小爬虫 在C#下有个很方便的类库 HtmlAgilityPa ...