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

一、概述

说到Android中的文件下载。Android API中明白要求将耗时的操作放到一个子线程中运行,文件的下载无疑是须要耗费时间的。所以要将文件的下载放到子线程中运行。

以下,我们一起来实现一个Android中利用多线程下载文件的小样例。

二、服务端准备

在这个小样例中我下面载有道词典为例。在网上下载有道词典的安装包,在eclipse中新建项目web。将下载的有道词典安装包放置在WebContent文件夹下,并将项目公布到Tomcat中,详细例如以下图所看到的

三、Android实现

1、布局

界面上自上而下放置一个TextView,用来提示文本框中输入的信息。一个文本框用来输入网络中下载文件的路径,一个Buttonbutton,点击下载文件,一个ProgressBar显示下载进度,一个TextView显示下载的百分比。

详细布局内容例如以下:

<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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity" > <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="下载路径" /> <EditText
android:id="@+id/ed_path"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="http://192.168.0.170:8080/web/youdao.exe"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下载"
android:onClick="download"/> <ProgressBar
android:id="@+id/pb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@android:style/Widget.ProgressBar.Horizontal"/> <TextView
android:id="@+id/tv_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="下载:0%"/> </LinearLayout>

2、自己定义ProgressBarListener监听器接口

新建自己定义ProgressBarListener监听器接口,这个接口中定义两个方法,void getMax(int length)用来获取下载文件的长度,void getDownload(int length);用来获取每次下载的长度,这种方法中主要是在多线程中调用,子线程中获取到的数据传递到这两个接口方法中,然后在这两个接口方法中通过Handler将对应的长度信息传递到主线程,更新界面显示信息。详细代码实现例如以下:

package com.example.inter;

/**
* 自己定义进度条监听器
* @author liuyazhuang
*
*/
public interface ProgressBarListener {
/**
* 获取文件的长度
* @param length
*/
void getMax(int length);
/**
* 获取每次下载的长度
* @param length
*/
void getDownload(int length);
}

3、自己定义线程类DownloadThread

这里通过继承Thread的方式来实现自己定义线程操作,在这个类中主要是实现文件的下载操作。在这个类中,定义了一系列与下载有关的实例变量来控制下载的数据,同一时候通过自己定义监听器ProgressBarListener中的void getDownload(int length)方法来跟新界面显示的进度信息。

详细实现例如以下:

package com.example.download;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL; import com.example.inter.ProgressBarListener; /**
* 自己定义线程类
* @author liuyazhuang
*
*/
public class DownloadThread extends Thread {
//下载的线程id
private int threadId;
//下载的文件路径
private String path;
//保存的文件
private File file;
//下载的进度条更新的监听器
private ProgressBarListener listener;
//每条线程下载的数据量
private int block;
//下载的開始位置
private int startPosition;
//下载的结束位置
private int endPosition; public DownloadThread(int threadId, String path, File file, ProgressBarListener listener, int block) {
this.threadId = threadId;
this.path = path;
this.file = file;
this.listener = listener;
this.block = block; this.startPosition = threadId * block;
this.endPosition = (threadId + 1) * block - 1;
} @Override
public void run() {
super.run();
try {
//创建RandomAccessFile对象
RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
//跳转到開始位置
accessFile.seek(startPosition);
URL url = new URL(path);
//打开http链接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置超时时间
conn.setConnectTimeout(5000);
//指定请求方式为GET方式
conn.setRequestMethod("GET");
//指定下载的位置
conn.setRequestProperty("Range", "bytes="+startPosition + "-" + endPosition);
//不用再去推断状态码是否为200
InputStream in = conn.getInputStream();
byte[] buffer = new byte[1024];
int len = 0;
while((len = in.read(buffer)) != -1){
accessFile.write(buffer, 0, len);
//更新下载进度
listener.getDownload(len);
}
accessFile.close();
in.close();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}

4、新建DownloadManager类

这个类主要是对下载过程的管理,包含下载设置下载后文件要保存的位置。计算多线程中每一个线程的数据下载量等等。

详细实现例如以下:

package com.example.download;

import java.io.File;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL; import android.os.Environment; import com.example.inter.ProgressBarListener; /**
* 文件下载管理器
* @author liuyazhuang
*
*/
public class DownloadManager {
//下载线程的数量
private static final int TREAD_SIZE = 3;
private File file;
/**
* 下载文件的方法
* @param path:下载文件的路径
* @param listener:自己定义的下载文件监听接口
* @throws Exception
*/
public void download(String path, ProgressBarListener listener) throws Exception{
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
if(conn.getResponseCode() == 200){
int filesize = conn.getContentLength();
//设置进度条的最大长度
listener.getMax(filesize);
//创建一个和server大小一样的文件
file = new File(Environment.getExternalStorageDirectory(), this.getFileName(path));
RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
accessFile.setLength(filesize);
//要关闭RandomAccessFile对象
accessFile.close(); //计算出每条线程下载的数据量
int block = filesize % TREAD_SIZE == 0 ? (filesize / TREAD_SIZE) : (filesize / TREAD_SIZE +1 ); //开启线程下载
for(int i = 0; i < TREAD_SIZE; i++){
new DownloadThread(i, path, file, listener, block).start();
}
}
} /**
* 截取路径中的文件名
* @param path:要截取文件名的路径
* @return:截取到的文件名
*/
private String getFileName(String path){
return path.substring(path.lastIndexOf("/") + 1);
}
}

5、完好MainActivity

在这个类中首先,找到页面中的各个控件,实现Buttonbutton的onClick事件,在onClick事件中开启一个线程进行下载操作,同一时候子线程中获取到的数据,通过handler与Message机制传递到主线程,更新界面显示。

详细实现例如以下:

package com.example.multi;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast; import com.example.download.DownloadManager;
import com.example.inter.ProgressBarListener; /**
* MainActivity整个应用程序的入口
* @author liuyazhuang
*
*/
public class MainActivity extends Activity { protected static final int ERROR_DOWNLOAD = 0;
protected static final int SET_PROGRESS_MAX = 1;
protected static final int UPDATE_PROGRESS = 2; private EditText ed_path;
private ProgressBar pb;
private TextView tv_info;
private DownloadManager manager;
//handler操作
private Handler mHandler = new Handler(){ public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case ERROR_DOWNLOAD:
//提示用户下载失败
Toast.makeText(MainActivity.this, "下载失败", Toast.LENGTH_SHORT).show();
break;
case SET_PROGRESS_MAX:
//得到最大值
int max = (Integer) msg.obj;
//设置进度条的最大值
pb.setMax(max);
break;
case UPDATE_PROGRESS:
//获取当前下载的长度
int currentprogress = pb.getProgress();
//获取新下载的长度
int len = (Integer) msg.obj;
//计算当前总下载长度
int crrrentTotalProgress = currentprogress + len;
pb.setProgress(crrrentTotalProgress); //获取总大小
int maxProgress = pb.getMax();
//计算百分比
float value = (float)currentprogress / (float)maxProgress;
int percent = (int) (value * 100);
//显示下载的百分比
tv_info.setText("下载:"+percent+"%");
break;
default:
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.ed_path = (EditText) super.findViewById(R.id.ed_path);
this.pb = (ProgressBar) super.findViewById(R.id.pb);
this.tv_info = (TextView) super.findViewById(R.id.tv_info);
this.manager = new DownloadManager(); } @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){
final String path = ed_path.getText().toString();
//下载
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
manager.download(path, new ProgressBarListener() {
@Override
public void getMax(int length) {
// TODO Auto-generated method stub
Message message = new Message();
message.what = SET_PROGRESS_MAX;
message.obj = length;
mHandler.sendMessage(message);
} @Override
public void getDownload(int length) {
// TODO Auto-generated method stub
Message message = new Message();
message.what = UPDATE_PROGRESS;
message.obj = length;
mHandler.sendMessage(message);
}
});
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
Message message = new Message();
message.what = ERROR_DOWNLOAD;
mHandler.sendMessage(message);
}
}
}).start();
}
}

6、添加权限

最后,别忘了给应用授权。这里要用到Android联网授权和向SD卡中写入文件的权限。

详细实现例如以下:

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

>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.multi"
android:versionCode="1"
android:versionName="1.0" > <uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.multi.MainActivity"
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>

四、执行效果

提醒:大家能够到http://download.csdn.net/detail/l1028386804/8899957 链接来获取完整的代码演示样例

Android之——多线程下载演示样例的更多相关文章

  1. android listview综合使用演示样例_结合数据库操作和listitem单击长按等事件处理

    本演示样例说明: 1.自己定义listview条目样式,自己定义listview显示列数的多少,灵活与数据库中字段绑定. 2.实现对DB的增删改查,而且操作后listview自己主动刷新. 3.响应用 ...

  2. Android之——流量管理程序演示样例

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/47680811 眼下.市面上有非常多管理手机流量的软件,能够让用户实时获取到自己手机 ...

  3. Android - 标准VideoView播放演示样例

    标准VideoView播放演示样例 本文地址: http://blog.csdn.net/caroline_wendy 在Android SDK中的ApiDemos内, 提供标准播放视频的代码,使用V ...

  4. [Android]RecyclerView的简单演示样例

    去年google的IO上就展示了一个新的ListView.它就是RecyclerView. 下面是官方的说明,我英语能力有限,只是我大概这么理解:RecyclerView会比ListView更具有拓展 ...

  5. JSP中文件的上传于下载演示样例

    一.文件上传的原理     1.文件上传的前提:         a.form表单的method必须是post         b.form表单的enctype必须是multipart/form-da ...

  6. Android SQLite 简单使用演示样例

    SQLite简单介绍 Google为Andriod的较大的数据处理提供了SQLite,他在数据存储.管理.维护等各方面都相当出色,功能也很的强大. 袖珍型的SQLite能够支持高达2TB大小的数据库, ...

  7. 在VC6.0中多线程编程演示样例(带同步信号量)

    直接上代码: #include <windows.h>//必要的头文件,使用Windows API函数 #include <stdio.h> int index = 0; in ...

  8. Androidclient与服务端交互之登陆演示样例

    今天了解了一下androidclient与服务端是如何交互的,发现事实上跟web有点类似吧,然后网上找了大神的登陆演示样例.是基于IntentService的 1.后台使用简单的servlet,支持G ...

  9. PopupMenu的演示样例

    弹出菜单是停靠在一个View上的一个模式菜单. 假设View对象下方有空间,那么弹出菜单将显示在停靠对象的下方,否则会显示在上方. 这是很实用的: 源代码地址:http://download.csdn ...

随机推荐

  1. python的unitest的简单使用

    python的unitest的简单使用 unittest提供一个TestLoader类用于自动创建一个测试集并把单个测试放入到测试集中. TestLoader自动运行测试用例以test开头的方法的测试 ...

  2. freenas 系统可能存在的bug

    1.portal 中ip端口显示有问题. 2.创建extend/target映射之后重启iscsi服务有的时候不能启动. 3.后台/usr /etc 重启系统会自动还原.

  3. 【Pytorch】关于torch.matmul和torch.bmm的输出tensor数值不一致问题

    发现 对于torch.matmul和torch.bmm,都能实现对于batch的矩阵乘法: a = torch.rand((2,3,10))b = torch.rand((2,2,10))### ma ...

  4. 微信小程序UI组件库 iView Weapp快速上手

    概述 今天在网上突然看到iView新出了一个微信小程序的组件库iView Weapp,自己就上手试了一下,发现用起来还是不错的,把自己使用的过程与大家分享下. 一 预览iView组件 1.可以在手机上 ...

  5. 导航栏 active 跟随鼠标效果

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. impdp导入

    //导入命令impdp 用户/密码@数据库链接 directory=数据库中映射路径 schemas=原用户 remap_schema=原用户:现用户 remap_tablespace=原表空间:现表 ...

  7. linux 负载各项查看命令

    free -h top -c 查看使用情况 sar -r/s/b 查看IO状态 iostat -x 1 10 查看服务器的状态 vmstat 查看内存使用率最后的前10个进程 ps -aux |sor ...

  8. Matlab学习笔记(一)

    一.MATLAB概述 (一)运行环境 命令行窗口(Command Window) 表 1-1 数据显示格式设置(e_one_1.m) 格式 实例 说明 format short 3.1416 小数点后 ...

  9. 集训第五周动态规划 C题 编辑距离

    Description Let x and y be two strings over some finite alphabet A. We would like to transform x int ...

  10. HDU 2475 Box

    Box Time Limit: 5000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 247564 ...