在日常项目开发中,关于图片批量下载,数据缓存的相关功能比比皆是,这次也是去年在项目中需要在本地缓存商品数据,所以用到了批量下载的功能,特此记录 ~
全局代码均使用的是伪代码 ,不能直接跑项目,更多的是提供解决思想和部分功能实现
Look here:glide 自带缓存,如果不是明确需要缓存到本地磁盘的话,可以使用glide节约时间,提升效率
- 单图下载:采用 Glide 框架为图片加载框架
- 批量下载:结合 Glide 框架与 递归 实现批量下载图片功能
基本配置
- 加入以下权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- build.gradle(app)
//glide图片框架
implementation 'com.github.bumptech.glide:glide:4.3.1'
annotationProcessor('com.github.bumptech.glide:compiler:4.3.1')
implementation 'com.github.bumptech.glide:okhttp3-integration:4.3.1'
//greenDao数据库框架
implementation 'org.greenrobot:greendao:3.3.0'
implementation 'org.greenrobot:greendao-generator:3.3.0'
Glide伪代码
public class GlideTool {
/**
* 主要用于监听Glide下载结果,成功或失败 ~
*/
public interface PicListener {
void success(File file);
void failure();
}
/**
* Glide图片下载
*/
public static synchronized void downImageFile(Context context, String imageUrl, PicListener listener) {
new Thread(new Runnable() {
@Override
public void run() {
FutureTarget<File> target = Glide.with(context)
.asFile()
.load(imageUrl)
.downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
try {
File file = target.get();
if (file != null) {
listener.success(file);
} else {
listener.failure();
}
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
我这里的实现步骤
,指的是常规项目中的一个实现过程
- 通过后台接口获取到我们需要缓存的数据(我网络框架用的是
RxAndroid+Retrofit
,可自行带入自己的网络框架)
我在项目中是要缓存商品的商品图,故此我获取的是一个商品的List,然后在进行批量下载
/**
* 商品列表
**/
public void interProductList() {
RetrofitManager.getInstance()
.getApiService()
.getProductList("Hint:自己的商品接口")
.compose(RxHelper.observableIO2Main(this))
.subscribe(new BaseObserver<"Hint:关于基类自行封装" > () {
@Override
public void onSuccess ("Hint:返回体类自行封装" response){
//可以在onCreate()创建productList用于存储商品数据
productList.clear();
List<ProductBean> interProductList = response.getProductList();
productList.addAll(interProductList);
//批量下载数据
downMoreImg(0,productList);
}
@Override
public void onFailure (Throwable e, String errorMsg){
}
});
}
ProductBean (伪类)
import java.io.Serializable;
/**
* @author Liu
* @date 2020/07/23
*/
public class ProductBean implements Serializable {
/**
* 商品id
*/
private String id;
/**
* 商品名称
*/
private String name;
/**
* 售价
*/
private String price;
/**
* 商品图片URL
*/
private String imageUrl;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
}
-
通过递归实现图片的批量下载
(同步线程 - 之所以未选择异步线程,主要是因为担心数据重复下载的问题)
优化方向
- 可以在图片下载失败的回调中进行错误数据记录,在所有图片下载完成后,再次下载之前的错误数据
- 可以在图片下载失败的回调中直接参与二次递归,不确定是否会有卡死现象
/**
* 批量缓存商品图片
*/
int tmpPosition = 0;
public synchronized void downMoreImg(int position, List<ProductBean> imgList) {
tmpPosition = position;
ProductBean productBean = imgList.get(tmpPosition);
String imageUrl = productBean.getImageUrl();
GlideTool.downImageFile(this, imageUrl, new GlideTool.PicListener() {
@Override
public void success(File file) {
Bitmap bitmap = BitmapFactory.decodeFile(file.toString());
//缓存商品数据到本地,采用GreenDao,如不用可删除
saveImage(productBean, bitmap, Constant.LocalPath.DEFAULT_PATH);
Log.e("tag", "下载成功:" + tmpPosition + " - position:" + position);
tmpPosition++;
if (tmpPosition < imgList.size()) {
downMoreImg(tmpPosition, imgList);
}
}
@Override
public void failure() {
Log.e("tag", "下载失败:" + tmpPosition);
}
});
}
-
缓存数据到本地数据库
(如果你的需求只是批量下载图片,那么无需往下看了)
关于本地数据缓存,我使用的 greenDao数据库存储 ,如果想偷懒的话也可以将数据存在sp里,但是要注意sp的安全性和体积较小的问题
/**
* 保存商品
*/
public void saveImage(ProductBean bean, Bitmap bitmap, String path) {
File file = new File(path);
if (!file.exists()) {
file.mkdir();
}
try {
String tmpImgPath = path + "/" + System.currentTimeMillis() + ".png";
FileOutputStream fileOutputStream = new FileOutputStream(tmpImgPath);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
fileOutputStream.close();
//我自己使用策略模式封装的GreenDao
DaoStrategy.getInstance(new LyProduct(bean.getCategoryId(), bean.getId(), bean.getName(), bean.getImageUrl(), tmpImgPath, bean.getStockNum(), bean.getUnit())).insert();
} catch (Exception e) {
LogTool.e(e.getMessage());
}
}