最近由于项目需要,我们要在某个地方一次下载大量的图片,并且将这些图片存放到SD卡中,将地址保存在数据库中,为了保证下载速度和程序运行的效率,我们考虑了以下几个问题:
1.为了保证操作效率,每张图片的下载和存储过程需要单独使用一个线程。
2.需要记录有几张图片下载成功,几张图片下载失败。
3.需要知道什么时候所有的图片下载任务结束。
4.为了保证CPU利用率,我们需要控制同一时刻最多可以开启多少线程。
对于问题1,开启线程下载图片的话,我们可以新建一个Thread()对象来进行图片下载的相关处理,多张图片可以进行循环开启线程,逻辑如下:
for(int i = 0;i < taskCount;i++){
new Thread(new Runnable(){
@override
public void run(){
//下载图片代码
...
//将图片存入SD卡的代码
...
//将图片地址存入数据库的代码
...
}
}).start();
}
对于问题2,我们可以设置几个变量来记录图片的下载情况
int totalTask;//一共需要下载多少张图片
int okTask;//成功的任务
int failTask;//失败的任务
这样,在使用的时候,我们可以
new Thread(new Runnable(){
@override
public void run(){
//下载图片代码
Bitmap bm = downloadPic(url);
if(bm != null){
//将图片存入SD卡的代码
...
//将图片地址存入数据库的代码
...
okTask++;
}else {
failTask++;
}
}
}).start();
问题3,判断什么时候所有任务才算结束,这就可以利用问题2中的3个变量,我们定义一个实时监听下载完成状态的方法
isDownloadComplete(final CompleteCallback callback){
new Thread(new Runnable() {
@Override
public void run() {
//这个循环等待所有任务完成
while(okTask + failTask < totalTask);
if(okTask == totalTask){
//所有图片下载成功
callback.onComplete();
} else {
//有些图片没有下载成功
callback.onFail();
}
}
}
回调的接口定义:
public interface CompleteCallback {
public void onComplete();
public void onFail();
}
第四个问题,也是一个很重要的问题,对于这个问题,我们可以将问题1中的循环开启多个线程改为用线程池对线程进行操作,这样既控制了同时启动的线程数量,又可以更好的管理启动的线程。
建立线程池,我们使用的是android 所带的ExecutorService ,关于这个服务,请参考下面的文章:
http://blog.csdn.net/hudashi/article/details/7008583
http://blog.sina.com.cn/s/blog_6151984a0100krj8.html
这样,问题1中的代码可以改为:
//nThreads 代表当前可以开启的线程数量
public void downloadPic() {
ExecutorService executorService = Executors.newFixedThreadPool(nThreads);
for(int i = 0;i < totalTask;i++){
executorService.submit(new Runnable() {
@Override
public void run() {
//下载图片代码
Bitmap bm = downloadPic(url);
if(bm != null){
//将图片存入SD卡的代码
...
//将图片地址存入数据库的代码
...
okTask++;
}else {
failTask++;
}
}
}
}
}
这样,我们就实现了一个批量下载图片的大体框架,我们假设将上述的过程封装成了一个类,那么我们在使用时就可以:
BitmapDownloadHelper helper = new BitmapDownloadHelper(需要传入的url数据等);
//这个就是上面的下载过程
helper.downloadPic();
helper.isDownloadComplete(new CompleteCallback(){
@override
public void onComplete(){
//下载成功的后续处理
}
@override
public void onFail(){
//下载失败的后续处理
}
});
好了,就写到这里,如有错误或者补充,还望不吝赐教。