版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】怎么在Android中利用AsyncTask实现一个多线程断点续传功能
这篇文章给大家介绍怎么在Android中利用AsyncTask实现一个多线程断点续传功能,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、实现原理多线程下载首先要通过每个文件总的下载线程数(我这里设定5个)来确定每个线程所负责下载的起止位置。
long
blockLength
=
mFileLength
/
DEFAULT_POOL_SIZE;
for
(int
i
=
0;
i
<
DEFAULT_POOL_SIZE;
i++)
{
long
beginPosition
=
i
*
blockLength;//每条线程下载的开始位置
long
endPosition
=
(i
+
1)
*
blockLength;//每条线程下载的结束位置
if
(i
==
(DEFAULT_POOL_SIZE
-
1))
{
endPosition
=
mFileLength;//如果整个文件的大小不为线程个数的整数倍,则最后一个线程的结束位置即为文件的总长度
}
}这里需要注意的是,文件大小往往不是线程个数的整数倍,所以最后一个线程的结束位置需要设置为文件长度。确定好每个线程的下载起止位置之后,需要设置http请求头来下载文件的指定位置:
//设置下载的数据位置beginPosition字节到endPosition字节
Header
header_size
=
new
BasicHeader("Range",
"bytes="
+
beginPosition
+
"-"
+
endPosition);
request.addHeader(header_size);以上是多线程下载的原理,但是还要实现断点续传需要在每次暂停之后记录每个线程已下载的大小,下次继续下载时从上次下载后的位置开始下载。一般项目中都会存数据库中,我这里为了简单起见直接存在了SharedPreferences中,已下载url和线程编号作为key值。@Override
protected
void
onPostExecute(Long
aLong)
{
Log.i(TAG,
"download
success
");
//下载完成移除记录
mSharedPreferences.edit().remove(currentThreadIndex).commit();
}
@Override
protected
void
onCancelled()
{
Log.i(TAG,
"download
cancelled
");
//记录已下载大小current
mSharedPreferences.edit().putLong(currentThreadIndex,
current).commit();
}下载的时候,首先获取已下载位置,如果已经下载过,就从上次下载后的位置开始下载:
//获取之前下载保存的信息,从之前结束的位置继续下载
//这里加了判断file.exists(),判断是否被用户删除了,如果文件没有下载完,但是已经被用户删除了,则重新下载
long
downedPosition
=
mSharedPreferences.getLong(currentThreadIndex,
0);
if(file.exists()
&&
downedPosition
!=
0)
{
beginPosition
=
beginPosition
+
downedPosition;
current
=
downedPosition;
synchronized
(mCurrentLength)
{
mCurrentLength
+=
downedPosition;
}
}二、完整代码package
com.bbk.lling.multithreaddownload;
import
android.app.Activity;
import
android.content.Context;
import
android.content.SharedPreferences;
import
android.os.AsyncTask;
import
android.os.Bundle;
import
android.os.Environment;
import
android.os.Handler;
import
android.os.Message;
import
android.util.Log;
import
android.view.View;
import
android.widget.ProgressBar;
import
android.widget.TextView;
import
android.widget.Toast;
import
org.apache.http.Header;
import
org.apache.http.HttpResponse;
import
org.apache.http.client.HttpClient;
import
org.apache.http.client.methods.HttpGet;
import
org.apache.http.impl.client.DefaultHttpClient;
import
org.apache.http.message.BasicHeader;
import
java.io.File;
import
java.io.IOException;
import
java.io.InputStream;
import
java.io.OutputStream;
import
java.io.RandomAccessFile;
import
.MalformedURLException;
import
java.util.ArrayList;
import
java.util.List;
import
java.util.concurrent.Executor;
import
java.util.concurrent.Executors;
public
class
MainActivity
extends
Activity
{
private
static
final
String
TAG
=
"MainActivity";
private
static
final
int
DEFAULT_POOL_SIZE
=
5;
private
static
final
int
GET_LENGTH_SUCCESS
=
1;
//下载路径
private
String
downloadPath
=
Environment.getExternalStorageDirectory()
+
File.separator
+
"download";
//
private
String
mUrl
=
"/mirrors/eclipse/technology/epp/downloads/release/juno/SR2/eclipse-java-juno-SR2-linux-gtk-x86_64.tar.gz";
private
String
mUrl
=
"/c4cb746699b92c9b6565cc65aa2e086552651f73c5d0e634a51f028e32af6abf3d68079eeb75401c76c9bb301e5fb71c144a704cb1a2f527a2e8ca3d6fe561dc5eaf6538e5b3ab0699308d13fe0b711a817c88b0f85a01a248df82824ace3cd7f2832c7c19173236";
private
ProgressBar
mProgressBar;
private
TextView
mPercentTV;
SharedPreferences
mSharedPreferences
=
null;
long
mFileLength
=
0;
Long
mCurrentLength
=
0L;
private
InnerHandler
mHandler
=
new
InnerHandler();
//创建线程池
private
Executor
mExecutor
=
Executors.newCachedThreadPool();
private
List<DownloadAsyncTask>
mTaskList
=
new
ArrayList<DownloadAsyncTask>();
@Override
protected
void
onCreate(Bundle
savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mProgressBar
=
(ProgressBar)
findViewById(R.gressbar);
mPercentTV
=
(TextView)
findViewById(R.id.percent_tv);
mSharedPreferences
=
getSharedPreferences("download",
Context.MODE_PRIVATE);
//开始下载
findViewById(R.id.begin).setOnClickListener(new
View.OnClickListener()
{
@Override
public
void
onClick(View
v)
{
new
Thread()
{
@Override
public
void
run()
{
//创建存储文件夹
File
dir
=
new
File(downloadPath);
if
(!dir.exists())
{
dir.mkdir();
}
//获取文件大小
HttpClient
client
=
new
DefaultHttpClient();
HttpGet
request
=
new
HttpGet(mUrl);
HttpResponse
response
=
null;
try
{
response
=
client.execute(request);
mFileLength
=
response.getEntity().getContentLength();
}
catch
(Exception
e)
{
Log.e(TAG,
e.getMessage());
}
finally
{
if
(request
!=
null)
{
request.abort();
}
}
Message.obtain(mHandler,
GET_LENGTH_SUCCESS).sendToTarget();
}
}.start();
}
});
//暂停下载
findViewById(R.id.end).setOnClickListener(new
View.OnClickListener()
{
@Override
public
void
onClick(View
v)
{
for
(DownloadAsyncTask
task
:
mTaskList)
{
if
(task
!=
null
&&
(task.getStatus()
==
AsyncTask.Status.RUNNING
||
!task.isCancelled()))
{
task.cancel(true);
}
}
mTaskList.clear();
}
});
}
/**
*
开始下载
*
根据待下载文件大小计算每个线程下载位置,并创建AsyncTask
*/
private
void
beginDownload()
{
mCurrentLength
=
0L;
mPercentTV.setVisibility(View.VISIBLE);
mProgressBar.setProgress(0);
long
blockLength
=
mFileLength
/
DEFAULT_POOL_SIZE;
for
(int
i
=
0;
i
<
DEFAULT_POOL_SIZE;
i++)
{
long
beginPosition
=
i
*
blockLength;//每条线程下载的开始位置
long
endPosition
=
(i
+
1)
*
blockLength;//每条线程下载的结束位置
if
(i
==
(DEFAULT_POOL_SIZE
-
1))
{
endPosition
=
mFileLength;//如果整个文件的大小不为线程个数的整数倍,则最后一个线程的结束位置即为文件的总长度
}
DownloadAsyncTask
task
=
new
DownloadAsyncTask(beginPosition,
endPosition);
mTaskList.add(task);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
mUrl,
String.valueOf(i));
}
}
/**
*
更新进度条
*/
synchronized
public
void
updateProgress()
{
int
percent
=
(int)
Math.ceil((float)mCurrentLength
/
(float)mFileLength
*
100);
//
Log.i(TAG,
"downloading
"
+
mCurrentLength
+
","
+
mFileLength
+
","
+
percent);
if(percent
>
mProgressBar.getProgress())
{
mProgressBar.setProgress(percent);
mPercentTV.setText("下载进度:"
+
percent
+
"%");
if
(mProgressBar.getProgress()
==
mProgressBar.getMax())
{
Toast.makeText(MainActivity.this,
"下载结束",
Toast.LENGTH_SHORT).show();
}
}
}
@Override
protected
void
onDestroy()
{
for(DownloadAsyncTask
task:
mTaskList)
{
if(task
!=
null
&&
task.getStatus()
==
AsyncTask.Status.RUNNING)
{
task.cancel(true);
}
mTaskList.clear();
}
super.onDestroy();
}
/**
*
下载的AsyncTask
*/
private
class
DownloadAsyncTask
extends
AsyncTask<String,
Integer
,
Long>
{
private
static
final
String
TAG
=
"DownloadAsyncTask";
private
long
beginPosition
=
0;
private
long
endPosition
=
0;
private
long
current
=
0;
private
String
currentThreadIndex;
public
DownloadAsyncTask(long
beginPosition,
long
endPosition)
{
this.beginPosition
=
beginPosition;
this.endPosition
=
endPosition;
}
@Override
protected
Long
doInBackground(String...
params)
{
Log.i(TAG,
"downloading");
String
url
=
params[0];
currentThreadIndex
=
url
+
params[1];
if(url
==
null)
{
return
null;
}
HttpClient
client
=
new
DefaultHttpClient();
HttpGet
request
=
new
HttpGet(url);
HttpResponse
response
=
null;
InputStream
is
=
null;
RandomAccessFile
fos
=
null;
OutputStream
output
=
null;
try
{
//本地文件
File
file
=
new
File(downloadPath
+
File.separator
+
url.substring(url.lastIndexOf("/")
+
1));
//获取之前下载保存的信息,从之前结束的位置继续下载
//这里加了判断file.exists(),判断是否被用户删除了,如果文件没有下载完,但是已经被用户删除了,则重新下载
long
downedPosition
=
mSharedPreferences.getLong(currentThreadIndex,
0);
if(file.exists()
&&
downedPosition
!=
0)
{
beginPosition
=
beginPosition
+
downedPosition;
current
=
downedPosition;
synchronized
(mCurrentLength)
{
mCurrentLength
+=
downedPosition;
}
}
//设置下载的数据位置beginPosition字节到endPosition字节
Header
header_size
=
new
BasicHeader("Range",
"bytes="
+
beginPosition
+
"-"
+
endPosition);
request.addHeader(header_size);
//执行请求获取下载输入流
response
=
client.execute(request);
is
=
response.getEntity().getContent();
//创建文件输出流
fos
=
new
RandomAccessFile(file,
"rw");
//从文件的size以后的位置开始写入,其实也不用,直接往后写就可以。有时候多线程下载需要用
fos.seek(beginPosition);
byte
buffer
[]
=
new
byte[1024];
int
inputSize
=
-1;
while((inputSize
=
is.read(buffer))
!=
-1)
{
fos.write(buffer,
0,
inputSize);
current
+=
inputSize;
synchronized
(mCurrentLength)
{
mCurrentLength
+=
inputSize;
}
this.publishProgress();
if
(isCancelled())
{
return
null;
}
}
}
catch
(MalformedURLException
e)
{
Log.e(TAG,
e.getMessage());
}
catch
(IOException
e)
{
Log.e(TAG,
e.getMessage());
}
finally{
try{
/*if(is
!=
null)
{
is.close();
}*/
if
(request
!=
null)
{
request.abort();
}
if(output
!=
null)
{
output.close();
}
if(fos
!=
null)
{
fos.close();
}
}
catch(Exception
e)
{
e.printStackTrace();
}
}
return
null;
}
@Override
protected
void
onPreExecute()
{
Log.i(TAG,
"download
begin
");
super.onPreExecute();
}
@
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- Unit 8 Summer holiday is coming!Lesson 47 公开课教学课件【七年级英语下册(冀教版)】
- (新人教版)高中英语必修第三册全册分单元教材解读(共5个单元)
- 市政改善城市供电设施
- 市政风景名胜区保护修缮
- 2024年特种作业考试-焊接与热切割作业笔试参考题库含答案
- 2024年火电电力职业技能鉴定考试-电力生产“1000个为什么”笔试参考题库含答案
- 2024年中国奥马珠单抗注射液行业研究报告
- 2024年浙江住院医师-浙江住院医师麻醉科笔试参考题库含答案
- 2024年法律知识法治建设知识竞赛-价格法知识竞赛笔试参考题库含答案
- 2024-2030全球与中国石油管道涂料市场现状及未来发展趋势
- 作物育种学各章主要知识点(杨存义)
- 听觉识别能力评估
- 服装设计师要掌握的服装用料计算方法
- 涤纶短丝工厂设计
- 离心泵毕业设计(共45页)
- 小学美术3.从不同角度画物体-课件-(1)ppt
- 中职《中国历史》试题
- 通用请假条Excel表格模板
- 医院有限空间作业管理制度(含应急预案)
- 个人参赛证明模板
- 海南省建筑工程竣工验收报告-表八(共7页)
评论
0/150
提交评论