标签:
------------------------------------------------------------------多线程下载操作---------------------------------------------------------------------多线程下载、断点续传,进度可视化。。。
1、新建一个布局文件,输入我们想要使用的线程的个数,包括一个主布局文件和一个progressBar
(1)一个包括三个控件的主布局
(2)一个只包含ProgressBar的子布局文件
2、找到三个控件,获取该Button控件的点击事件,点击开始下载
(1)获取用户输入线程的个数
(2)清空所有ProgressBar子控件
(3)根据线程数添加相应数量的ProgressBar
(4)在子线程中运行download()函数,因为主线程不能做时间太长的操作
3、进入download()函数,为每个线程设定下载的开始和结束为止
(1)根据url请求网络资源
(2)获取下载资源的大小,并在本地创建占位符
(3)要分配每个线程下载文件的开始位置和结束位置
(4)开启线程去执行下载
4、开启线程下载,需要定义一个线程下载类继承并重写run()方法
(1)通过map获取当前线程对应ProgressBar
(2)建立一个SharedPreferences的操作类用来存取断点信息
(3)设置分段下载的头信息。Range信息:做分段数据请求用的,也就是设置从哪里下载到哪里
(4)请求部分资源成功,开始一边从服务器读取一边写入sdcard
(5)写入过程中将下载进度保存的SharedPreferences中,设置ProgressBar的显示情况
二、---布局创建---
(1)一个包括三个控件的主布局
<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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<EditText
android:id="@+id/et_threadCount"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/bt_download"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="立即下载" />
<LinearLayout
android:id="@+id/ll_progress_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
style="?android:attr/progressBarStyleHorizontal"
android:layout_height="match_parent" >
</ProgressBar>
(3)初步的界面展示如下
如下是一些全局变量的初始化,以及我们在点击“开始下载”之后处理的内容:
(1)定义一些全局变量,这些我们在下面要使用到
public class MainActivity extends Activity implements OnClickListener{
private EditText et_threadCount;
private Context mContext;
private LinearLayout ll_progress_layout;
private int threadCount = 0; //开启3个线程
private int blockSize = 0; //每个线程下载的大小
private int runningTrheadCount = 0;//当前运行的线程数
private String path = "http://115.25.200.74:8080/itheima74/feiq.exe";
private Map<Integer,ProgressBar> map = new HashMap<Integer, ProgressBar>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
findViewById(R.id.bt_download).setOnClickListener(this);
ll_progress_layout = (LinearLayout) findViewById(R.id.ll_progress_layout);
et_threadCount = (EditText) findViewById(R.id.et_threadCount);
}
public void onClick(View v) {
//获取用户输入的线程数
String trim = et_threadCount.getText().toString().trim();
threadCount = Integer.parseInt(trim);
// 清空所有的子空间
ll_progress_layout.removeAllViews();
//根据线程数添加相应数量的ProgressBar
for(int i =0 ;i < threadCount;i++ ){
ProgressBar progressbar = (ProgressBar)View.inflate(mContext, R.layout.child_progressbar_layout, null);
map.put(i, progressbar);//将ProgressBar放到map中,方便在线程中获取并设置进度
//展示progressbar
ll_progress_layout.addView(progressbar);
}
new Thread(new Runnable() {
@Override
public void run() {
download();
}
}).start();
}
(1)根据url请求网络资源
//1.请求url地址获取服务端资源的大小
URL url = new URL(path);
HttpURLConnection openConnection = (HttpURLConnection) url.openConnection();
openConnection.setRequestMethod("GET");
openConnection.setConnectTimeout(10*1000);
int code = openConnection.getResponseCode();
if(code == 200){
//获取资源的大小
int filelength = openConnection.getContentLength();
//2.在本地创建一个与服务端资源同样大小的一个文件(占位)
RandomAccessFile randomAccessFile = new RandomAccessFile(new File(getFileName(path)), "rw");
randomAccessFile.setLength(filelength);//设置随机访问文件的大小
//3.要分配每个线程下载文件的开始位置和结束位置。
blockSize = filelength/threadCount;//计算出每个线程理论下载大小
for(int threadId =0 ;threadId < threadCount;threadId++){
int startIndex = threadId * blockSize;//计算每个线程下载的开始位置
int endIndex = (threadId+1)*blockSize -1;//计算每个线程下载的结束位置
//如果是最后一个线程,结束位置需要单独计算
if(threadId == threadCount-1){
endIndex = filelength -1;
}
//4.开启线程去执行下载
new DownloadThread(threadId, startIndex, endIndex).start();
(1)基本参数的定义和初始化
private int threadId;
private int startIndex;
private int endIndex;
private int lastPostion;
private int currentThreadTotalProgress;
public DownloadThread(int threadId,int startIndex,int endIndex){
this.threadId = threadId;
this.startIndex = startIndex;
this.endIndex = endIndex;
// 进度条的最大值
this.currentThreadTotalProgress = endIndex -startIndex +1;
}
package com.iigt.download;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
public class SharedUtils {
public static int getLastPosition(Context context,int threadId){
SharedPreferences defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
return defaultSharedPreferences.getInt("lastPostion"+threadId, -1);
}
public static void setLastPosition(Context context,int threadId,int position){
SharedPreferences defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
defaultSharedPreferences.edit().putInt("lastPostion"+threadId, position).commit();
}
}
//分段请求网络连接,分段保存文件到本地
try{
URL url = new URL(path);
HttpURLConnection openConnection = (HttpURLConnection) url.openConnection();
openConnection.setRequestMethod("GET");
openConnection.setConnectTimeout(10*1000);
System.out.println("理论上下载: 线程:"+threadId+",开始位置:"+startIndex+";结束位置:"+endIndex);
if(SharedUtils.getLastPosition(mContext, threadId) != -1){
lastPostion = SharedUtils.getLastPosition(mContext, threadId);
//说明该线程已经下载完成
if(lastPostion == endIndex+1){
progressBar.setProgress(currentThreadTotalProgress);
runningTrheadCount = runningTrheadCount -1;
}
//设置分段下载的头信息。 Range:做分段数据请求用的。
openConnection.setRequestProperty("Range", "bytes:"+lastPostion+"-"+endIndex);//bytes:0-500:请求服务器资源中0-500之间的字节信息 501-1000:
System.out.println("实际下载: 线程:"+threadId+",开始位置:"+lastPostion+";结束位置:"+endIndex);
}else{
lastPostion = startIndex;
//设置分段下载的头信息。 Range:做分段数据请求用的。
openConnection.setRequestProperty("Range", "bytes:"+lastPostion+"-"+endIndex);
System.out.println("实际下载: 线程:"+threadId+",开始位置:"+lastPostion+";结束位置:"+endIndex);
}(4)请求部分资源成功,开始一边从服务器读取一边写入sdcard
if(openConnection.getResponseCode() == 206){//200:请求全部资源成功, 206代表部分资源请求成功
InputStream inputStream = openConnection.getInputStream();
//请求成功将流写入本地文件中,已经创建的占位那个文件中
RandomAccessFile randomAccessFile = new RandomAccessFile(new File(getFileName(path)), "rw");
randomAccessFile.seek(lastPostion);//设置随机文件从哪个位置开始写。
//将流中的数据写入文件
byte[] buffer = new byte[1024*100];
int length = -1;
int total = 0;//记录本次线程下载的总大小
while((length= inputStream.read(buffer)) !=-1){
randomAccessFile.write(buffer, 0, length);
total = total+ length;
//去保存当前线程下载的位置,保存到文件中
int currentThreadPostion = lastPostion + total;//计算出当前线程本次下载的位置
SharedUtils.setLastPosition(mContext, threadId, currentThreadPostion);
//计算线程下载的进度并设置进度
int currentprogress = currentThreadPostion -startIndex;
progressBar.setMax(currentThreadTotalProgress);//设置进度条的最大值
progressBar.setProgress(currentprogress);//设置进度条当前进度
}
//关闭相关的流信息
inputStream.close();
randomAccessFile.close();
System.out.println("线程:"+threadId+",下载完毕"); public String getFileName(String url){
return Environment.getExternalStorageDirectory() + "/"+ url.substring(url.lastIndexOf("/")+1);
}
public String getFilePath(){
return Environment.getExternalStorageDirectory() + "/";
}-----------------------------------------------------------------文件上传操作--------------------------------------------------------------------
1、客户端上传操作
(1)编写布局文件,一个EditText一个Button
(2)获取输入的文件地址
(3)使用开源Utils做上传操作
2、服务器端接收操作
(1)首先判断上传的数据是表单数据还是带文件的数据
(2)如果是带文件的数据,在本地创建文件目录
(3)判断文件的类型,表单打印,文件类型就上传
二、---布局创建---
(1)编写布局文件,一个EditText一个Button
<RelativeLayout 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"
tools:context=".MainActivity" >
<EditText
android:id="@+id/et_filepath"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Button
android:onClick="fileupload"
android:text="上传"
android:layout_below="@id/et_filepath"
android:id="@+id/bt_upload"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
(1)获取输入的文件地址
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void fileupload(View v){
try{
EditText et_filepath = (EditText) findViewById(R.id.et_filepath);
//获取输入的文件地址
String filepath = et_filepath.getText().toString().trim();
//使用开源Utils做上传操作
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
RequestParams params = new RequestParams();
params.put("filename", new File(filepath));
//url : 请求服务器的url
asyncHttpClient.post("http://115.25.200.74:8080/itheima74/servlet/UploaderServlet", params, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
if(statusCode == 200){
Toast.makeText(MainActivity.this, "上传成功", 0).show();
}
}
@Override
public void onFailure(int statusCode, Header[] headers,
byte[] responseBody, Throwable error) {
}
});
}catch (Exception e) {
e.printStackTrace();
}
先判断数据类型,接着再判断文件类型,如果是文件的话就上传操作,是表单的话进行打印操作
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//首先判断上传的数据是表单数组数据还是一个带文件的数据
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) { //如果是true,说明是一个带有文件的数据
//拿到servlet的真实路径
String realpath = request.getSession().getServletContext().getRealPath("/files");
//打印一下路径
System.out.println("realpath-"+realpath);
File dir = new File(realpath);
if (!dir.exists())
dir.mkdirs(); //如果目标不在就把这个目录给创建出来
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory); //获得上传文件的对象upload
upload.setHeaderEncoding("UTF-8");
try {
//判断一下上传的数据类型
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items) {
if (item.isFormField()) { //上传的数据类型是一个表单类型
String name1 = item.getFieldName();// 得到请求参数的名称
String value = item.getString("UTF-8");//得到参数值?
System.out.println(name1 + "=" + value);
} else {
//说明这是一个文件类型,进行上传
item.write(new File(dir, System.currentTimeMillis()
+ item.getName().substring(item.getName().lastIndexOf("."))));
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
}
}
}
1、文件的下载操作在安卓2.3上可以正常的使用,但是在安卓4.1上就不能正常运行,由于是刚刚学习,也不知道怎么解决
2、下载中开始开启3个线程,然后中断,再填写5个线程,这时只有最后两个线程运行了
标签:
原文地址:http://blog.csdn.net/jinhuoxingkong/article/details/51982828