转载请注明出处: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. Relational Algebra 关系代数

    Relational Algebra Relational Algebra is the mathematical basis for the query language SQL Introduct ...

  2. jQuery 价格显示 前面位数与后面两位显示不同样式(一大一小)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. js 作用域 ?????

    ///*第一种情况 */ //var mycars = new Array() //mycars[0] = 0; //mycars[1] = 1; //mycars[2] = 2; //functio ...

  4. linux 配置Java、Mysql、Tomcat、Redis开发环境

    1.安装四个依赖 以下四个依赖必须按顺序联网安装:yum install glibc.i686yum -y install libaio.so.1 libgcc_s.so.1 libstdc++.so ...

  5. html引用ttf字体文件

    在样式表如此定义: @font-face { font-family: MyFontName;//自定义字体名称 src: url(../Gloss_And_Bloom.ttf) } 然后,具体使用: ...

  6. C#面试问题及答案

    1.遇到高并发的问题如何解决? 优化SQL语句 多线程 分布式服务器 集群 拆表2.Dictionary和ConurrentDictionary的区别? 后者是线程安全的 前者适用于单线程3.Dict ...

  7. JavaSE-22 反射

    学习要点 反射概念 反射的应用 反射概述 1  反射机制 定义 Java反射机制是指在程序在运行状态中,动态获取信息以及动态调用对象方法的功能. Java反射的动态性质:运行时生成对象实例.运行期间调 ...

  8. 配置Mysql审计

    mysql-audit.json:Mysql审计日志 插件下载地址: https://bintray.com/mcafee/mysql-audit-plugin/release/1.1.4-725#f ...

  9. hdu 2377 Bus Pass

    Bus Pass Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  10. Sublime text 3搭建Python开发环境及常用插件安装 转载

    Sublime text 3搭建Python开发环境及常用插件安装 一.环境准备 1.官方网站地址 2.Windows 10 3.Sublime Text 3 + 官网购买license(Just a ...