Android之——多线程下载演示样例
转载请注明出处: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之——多线程下载演示样例的更多相关文章
- android listview综合使用演示样例_结合数据库操作和listitem单击长按等事件处理
本演示样例说明: 1.自己定义listview条目样式,自己定义listview显示列数的多少,灵活与数据库中字段绑定. 2.实现对DB的增删改查,而且操作后listview自己主动刷新. 3.响应用 ...
- Android之——流量管理程序演示样例
转载请注明出处:http://blog.csdn.net/l1028386804/article/details/47680811 眼下.市面上有非常多管理手机流量的软件,能够让用户实时获取到自己手机 ...
- Android - 标准VideoView播放演示样例
标准VideoView播放演示样例 本文地址: http://blog.csdn.net/caroline_wendy 在Android SDK中的ApiDemos内, 提供标准播放视频的代码,使用V ...
- [Android]RecyclerView的简单演示样例
去年google的IO上就展示了一个新的ListView.它就是RecyclerView. 下面是官方的说明,我英语能力有限,只是我大概这么理解:RecyclerView会比ListView更具有拓展 ...
- JSP中文件的上传于下载演示样例
一.文件上传的原理 1.文件上传的前提: a.form表单的method必须是post b.form表单的enctype必须是multipart/form-da ...
- Android SQLite 简单使用演示样例
SQLite简单介绍 Google为Andriod的较大的数据处理提供了SQLite,他在数据存储.管理.维护等各方面都相当出色,功能也很的强大. 袖珍型的SQLite能够支持高达2TB大小的数据库, ...
- 在VC6.0中多线程编程演示样例(带同步信号量)
直接上代码: #include <windows.h>//必要的头文件,使用Windows API函数 #include <stdio.h> int index = 0; in ...
- Androidclient与服务端交互之登陆演示样例
今天了解了一下androidclient与服务端是如何交互的,发现事实上跟web有点类似吧,然后网上找了大神的登陆演示样例.是基于IntentService的 1.后台使用简单的servlet,支持G ...
- PopupMenu的演示样例
弹出菜单是停靠在一个View上的一个模式菜单. 假设View对象下方有空间,那么弹出菜单将显示在停靠对象的下方,否则会显示在上方. 这是很实用的: 源代码地址:http://download.csdn ...
随机推荐
- 引用类型 (Reference Type Matters)、扩展与派发方式
引用类型 (Reference Type Matters) 引用的类型决定了派发的方式. 这很显而易见, 但也是决定性的差异. 一个比较常见的疑惑, 发生在一个协议拓展和类型拓展同时实现了同一个函数的 ...
- laravel学习:模块化caffeinated
# Modules Extract and modularize your code for maintainability. Essentially creates "mini-larav ...
- WebStorm改变字体大小以及更换背景颜色
参考文章:https://blog.csdn.net/weixin_42676530/article/details/82961279
- zabbix4.2学习笔记--zabbix安装
环境 系统信息 发行版 版本 ip 关系 主机名 centos 7.5 192.168.181.135 服务端 server centos 7.5 192.168.181.136 客户端 client ...
- zabbix4.2学习笔记--监控tomcat
zabbix提供了一个java gateway的应用去监控jmx(Java Management Extensions,即Java管理扩展)是一个为应用程序.设备.系统等植入管理功能的框架 环境 主机 ...
- 解决java web项目导入后出现的问题 ---cannot be read or is not a valid ZIP file
导入以前的web项目后会出现以下三个错误: 1. Archive for required library: ‘WebContent/WEB-INF/lib/readme.txt’ in projec ...
- JS授权
(function(){ var origin_url = location.href; var oauth_url = 'https://vx.mcilife.com/weixin/api/oaut ...
- 笔试算法题(34):从数字序列中寻找仅出现一次的数字 & 最大公约数(GCD)问题
出题:给定一个数字序列,其中每个数字最多出现两次,只有一个数字仅出现了一次,如何快速找出其中仅出现了一次的数字: 分析: 由于知道一个数字异或操作它本身(X^X=0)都为0,而任何数字异或操作0都为它 ...
- 记一次被面试的final问题
---- 前言 今天面试被问到了,我们都知道final修饰的东西是不可变的,那么是值不可变还是其地址不可变?一脸懵逼,回来查阅一番,总结一下 --- final与数据 在日常行为下,一般数据指的都是基 ...
- linux文件及目录的权限管理
一.文件的权限 1.文件权限的查看 命令:ls -l 可以使用ll命令代替 ls -l 2.ls -l 所包含的信息 (1)权限信息 (-rw-r--r-- ) 一共有10位 a.第一位:表示文件信息 ...