android glide加载进度,Glide

前言

Glide无疑是一款非常优秀的图片加载框架,但是他并没有支持显示图片加载的进度.

那么我们遇到这种需求的时候应该怎么办?自己写一个图片加载框架么?

不,我们肯定是选择自己来扩展这个框架,使得Glide”支持”显示进度

GlideImageView 用来控制start & autoStart , 用来显示 progress , error

OkHttp 用来支持进度的回调

思考

为什么我要选择使用OkHttp来改造那?

@Override

public void registerComponents(Context context, Glide glide, Registry registry) {

registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());

}

我们可以看到,ModelLoaderFactory是我们自己传进去的,那么我只要持有这个ModelLoaderFactory不就可以知道进度了么?

追踪源码发现了初始化OkHttpClient的方法,internalClient 是Call.Factory类型的,而OkHttpClient是Call.Factory的实现类.

/**

* Constructor for a new Factory that runs requests using a static singleton client.

*/

public Factory() {

this(getInternalClient());

}

/**

* Constructor for a new Factory that runs requests using given client.

*

* @param client this is typically an instance of {@code OkHttpClient}.

*

* 看到这个有参的构造函数了么?还是Public的..

*/

public Factory(@NonNull Call.Factory client) {

this.client = client;

}

private static Call.Factory getInternalClient() {

if (internalClient == null) {

synchronized (Factory.class) {

if (internalClient == null) {

internalClient = new OkHttpClient();

}

}

}

return internalClient;

}

那么,可以确定替换OkHttpClient的思路是正确的,下面我们来实现一下

deff870a873e5b69b596bf3ce9d42b44.png

OkHttpLoadImage 提供OkHttpClient并添加拦截器

OnProgressListener 由需要显示进度的View实现,提供一个Url,回调progress

OkHttpClient 的实例

HashMap实际上存放的是View自己

ProgressResponseBody 对外提供当前下载的进度

LoadImageView 记录当前url,显示进度

GlideLoaderModule @GlideModule

通过new OkHttpUrlLoader.Factory(OkHttpLoadImage.INSTANCE())替代默认的OkHttpClient

代码实现

OkHttpLoadImage

该类提供一个OkHttpClient的实例,在这个实例中添加一个NetworkInterceptor,这个拦截器提供当前下载的进度

/**

* If you have any questions, you can contact by email {wangzhumoo@gmail.com}

*

* @author 王诛魔 2018/8/9 下午6:10

*/

public final class OkHttpLoadImage {

//一定要记得unRegister,这里存放的是key以及OnProgressListener

//实际上,我们最好采用软引用,这样更加的安全,毕竟我们无法感知View的生命周期

private static HashMap progressListenerMap;

//添加了拦截的OkHttpClient

private OkHttpClient okHttpClient;

static {

progressListenerMap = new HashMap<>();

}

private OkHttpLoadImage() {

initOkHttp();

}

/**

* 构建一个OkHttp的实例

* ProgressResponseBody 是一个比较关键的类,他提供了进度

*/

private void initOkHttp() {

okHttpClient = new OkHttpClient.Builder()

.addNetworkInterceptor(chain -> {

Request request = chain.request();

Response response = chain.proceed(request);

ProgressResponseBody body = new ProgressResponseBody(response, request.url().toString());

//添加监听,使得当前类知道进度

body.addOnResponseListener(responseListener);

return response.newBuilder()

.body(body)

.build();

})

.build();

}

private static class SingletonHolder {

private static OkHttpLoadImage instance = new OkHttpLoadImage();

}

public static OkHttpClient INSTANCE(){

return SingletonHolder.instance.okHttpClient;

}

private static ProgressResponseBody.OnResponseListener responseListener = new ProgressResponseBody.OnResponseListener() {

@Override

public void update(String key, float progress) {

//去寻找这个key,并传回去当前的进度

OnProgressListener listener = progressListenerMap.get(key);

if (listener != null) {

listener.onProgress(progress);

}

}

};

/**

* 注册进度的回调

*/

public static void register(OnProgressListener listener) {

//可能会有多个View注册,但是我们只回调当前这个

progressListenerMap.put(listener.getKey(), listener);

}

/**

* 取消监听

*

* @param listener view

*/

public static void unRegister(OnProgressListener listener) {

progressListenerMap.remove(listener.getKey());

}

/**

* 监听进度的接口

*/

public interface OnProgressListener {

//回调当前的进度给View

void onProgress(float progress);

//获取当前View资源的key(URL即可)

String getKey();

}

}

ProgressResponseBody

这个东西,网上到处都是

public class ProgressResponseBody extends ResponseBody{

//OkHttpLoadImage中传进来的response

private final ResponseBody responseBody;

private String url;

private BufferedSource bufferedSource;

public ProgressResponseBody(Response response,String url) {

this.responseBody = response.body();

this.url = url;

}

@Override

public MediaType contentType() {

return responseBody.contentType();

}

@Override

public long contentLength() {

return responseBody.contentLength();

}

@Override

public BufferedSource source() {

if (bufferedSource == null) {

bufferedSource = Okio.buffer(source(responseBody.source()));

}

return bufferedSource;

}

private Source source(BufferedSource source) {

return new ForwardingSource(source) {

long totalBytes = 0L;

@Override

public long read(Buffer sink, long byteCount) throws IOException {

long bytesRead = super.read(sink, byteCount);

// read() returns the number of bytes read, or -1 if this source is exhausted.

totalBytes += bytesRead != -1 ? bytesRead : 0;

if (listener != null) {

//注意这块的 1.0 * , 要不两个long除法会一直是 0

listener.update(url, (float) 1.0 * totalBytes/contentLength());

}

return bytesRead;

}

};

}

private OnResponseListener listener;

public void addOnResponseListener(OnResponseListener listener){

this.listener = listener;

}

public interface OnResponseListener{

void update(String key,float progress);

}

}

LoadImageView/**

* If you have any questions, you can contact by email {wangzhumoo@gmail.com}

*

* @author 王诛魔 2018/8/9 下午5:59

*/

public class LoadImageView extends AppCompatImageView implements OkHttpLoadImage.OnProgressListener{

private Paint mPaint;

private float progress;

private String url;

public LoadImageView(Context context) {

this(context,null);

}

public LoadImageView(Context context, @Nullable AttributeSet attrs) {

this(context, attrs,0);

}

public LoadImageView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

public void setImageUrl(String url){

this.url = url;

//此时开始加载

OkHttpLoadImage.register(this);

ImageLoader.LoaderImg(getContext(),url).into(this);

Glide.with(this).load(url).into(this);

}

/**

* 初始化工具

*/

private void init() {

mPaint = new Paint();

mPaint.setColor(Color.BLACK);

mPaint.setAntiAlias(true);

mPaint.setStrokeWidth(5);

mPaint.setTextSize(50);

}

@SuppressLint("DefaultLocale")

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

canvas.drawText(String.format("Already : %d",(int)(100 * progress)),100,100,mPaint);

}

public void progress(float progress){

this.progress = progress;

invalidate();

}

@Override

public void onProgress(float progress) {

post(() -> progress(progress));

}

@Override

public String getKey() {

return url;

}

public boolean isLoaded(){

return progress == 1F;

}

}

GlideLoaderModule/**

* If you have any questions, you can contact by email {wangzhumoo@gmail.com}

*

* @author 王诛魔 2017/8/9 下午12:16

*

*/

@GlideModule

public final class GlideLoaderModule extends AppGlideModule {

@Override

public void applyOptions(Context context, GlideBuilder builder) {

RequestOptions options = new RequestOptions()

.centerCrop()

.placeholder(R.drawable.default_images_load)

.error(R.drawable.default_images_load)

.priority(Priority.HIGH)

.format(DecodeFormat.PREFER_ARGB_8888)

.diskCacheStrategy(DiskCacheStrategy.ALL);

int maxMemory = (int) Runtime.getRuntime().maxMemory();

int memoryCacheSize = maxMemory / 8;

//设置内存缓存大小

File cacheDir = new File(ApiConstants.INSTANCE.getIMAGE_PATH() + File.separator);

if(!cacheDir.exists()){

cacheDir.mkdirs();

}

int diskCacheSize = 1024 * 1024 * 512;

//设置磁盘缓存大小

builder.setMemoryCache(new LruResourceCache(memoryCacheSize));

builder.setDiskCache(new DiskLruCacheFactory(cacheDir.getPath(), "Images", diskCacheSize));

builder.setDefaultRequestOptions(options);

}

@Override

public void registerComponents(Context context, Glide glide, Registry registry) {

registry.replace(GlideUrl.class, InputStream.class,

new OkHttpUrlLoader.Factory(OkHttpLoadImage.INSTANCE()));

}

}

使用

0a93cf8fc8e9d876ee2bcdf4c5cd3c5d.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值