
Glide源码学习八:实现带进度的Glide图片加载功能
发布日期:2021-05-14 18:09:50
浏览次数:18
分类:精选文章
本文共 9631 字,大约阅读时间需要 32 分钟。
如何在Glide中实现下载进度监听功能
一、项目准备工作
创建新项目
创建一个名为GlideProgressTest
的新项目,用于测试Glide的自定义下载进度功能。 添加依赖库
在app/build.gradle
中添加必要的组件依赖: dependencies { compile 'com.github.bumptech.glide:glide:3.7.0' compile 'com.squareup.okhttp3:okhttp:3.9.0'}
网络权限声明
在AndroidManifest.xml
文件中添加网络权限: 二、替换Glide的HTTP通讯组件到OkHttp
创建自定义OkHttpFetcher类
这个类实现DataFetcher
接口,用于处理HTTP请求: public class OkHttpFetcher implements DataFetcher{ private final OkHttpClient client; private final GlideUrl url; private InputStream stream; private ResponseBody responseBody; private volatile boolean isCancelled; public OkHttpFetcher(OkHttpClient client, GlideUrl url) { this.client = client; this.url = url; } @Override public InputStream loadData(Priority priority) throws Exception { Request.Builder requestBuilder = new Request.Builder() .url(url.toStringUrl()); for (Map.Entry headerEntry : url.getHeaders().entrySet()) { requestBuilder.addHeader(headerEntry.getKey(), headerEntry.getValue()); } Request request = requestBuilder.build(); if (isCancelled) { return null; } Response response = client.newCall(request).execute(); responseBody = response.body(); if (!response.isSuccessful() || responseBody == null) { throw new IOException("Request failed with code: " + response.code()); } stream = ContentLengthInputStream.obtain( responseBody.byteStream(), responseBody.contentLength()); return stream; } @Override public void cleanup() { try { if (stream != null) { stream.close(); } if (responseBody != null) { responseBody.close(); } } catch (IOException e) { e.printStackTrace(); } } @Override public String getId() { return url.getCacheKey(); } @override public void cancel() { isCancelled = true; }}
创建OkHttpGlideUrlLoader类
该类实现ModelLoader
接口,用于加载数据: public class OkHttpGlideUrlLoader implements ModelLoader{ private OkHttpClient okHttpClient; public static class Factory implements ModelLoaderFactory { private OkHttpClient client; public Factory() {} public Factory(OkHttpClient client) { this.client = client; } @Override public ModelLoader build( Context context, GenericLoaderFactory fyFactory) { return new OkHttpGlideUrlLoader(getOkHttpClient()); } @override public void teardown() {} } public OkHttpGlideUrlLoader(OkHttpClient client) { this.okHttpClient = client; } @Override public DataFetcher getResourceFetcher(GlideUrl model, int width, int height) { return new OkHttpFetcher(okHttpClient, model); }}
注册组件到Glide中
在MyGlideModule
类中注册自定义组件: public class MyGlideModule implements GlideModule { @Override public void applyOptions(Context context, GlideBuilder builder) {} @Override public void registerComponents(Context context, Glide glide) { OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.addInterceptor(new ProgressInterceptor()); OkHttpClient okHttpClient = builder.build(); glide.register( GlideUrl.class, Inputstream.class, new OkHttpGlideUrlLoader.Factory(okHttpClient)); }}
声明Glide模块
在AndroidManifest.xml
中添加模块声明: 三、实现下载进度监听
创建ProgressInterceptor拦截器类
该类实现Interceptor
接口,用于拦截HTTP请求并处理进度信息: public class ProgressInterceptor implements Interceptor { private static final MapLISTENER_MAP = new HashMap<>(); public static void addListener(String url, ProgressListener listener) { LISTENER_MAP.put(url, listener); } public static void removeListener(String url) { LISTENER_MAP.remove(url); } @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response response = chain.proceed(request); String url = request.url().toString(); ResponseBody body = response.body(); Response newResponse = response .newBuilder() .body(new ProgressResponseBody(url, body)) .build(); return newResponse; }}
创建ProgressResponseBody类
该类继承ResponseBody
,用于处理下载流并计算进度: public class ProgressResponseBody extends ResponseBody { private static final String TAG = "ProgressResponseBody"; private BufferedSource bufferedSource; private ProgressListener listener; private ResponseBody responseBody; public ProgressResponseBody(String url, ResponseBody responseBody) { this.responseBody = responseBody; listener = ProgressInterceptor.LISTENER_MAP.get(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(new ProgressSource(responseBody.source())); } return bufferedSource; } private class ProgressSource extends ForwardingSource { private long totalBytesRead; private int currentProgress; ProgressSource(Source source) { super(source); } @Override public long read(Buffer sink, long byteCount) throws IOException { long bytesRead = super.read(sink, byteCount); long fullLength = responseBody.contentLength(); if (bytesRead == -1) { totalBytesRead = fullLength; } else { totalBytesRead += bytesRead; } int progress = (int) (100f * totalBytesRead / fullLength); Log.d(TAG, "download progress is " + progress); boolean hasChanged = progress != currentProgress; currentProgress = progress; if (listener != null && hasChanged) { listener.onProgress(progress); } return bytesRead; } }}
在Glide中启用拦截器
修改MyGlideModule
类,使其在注册组件时启用OkHttp客户端和拦截器: public class MyGlideModule implements GlideModule { @Override public void applyOptions(Context context, GlideBuilder builder) {} @Override public void registerComponents(Context context, Glide glide) { OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.addInterceptor(new ProgressInterceptor()); OkHttpClient okHttpClient = builder.build(); glide.register( GlideUrl.class, Inputstream.class, new OkHttpGlideUrlLoader.Factory(okHttpClient)); }}
四、集成进度显示到用户界面
在MainActivity中创建ProgressDialog
在MainActivity
中定义并初始化一个进度条: public class MainActivity extends AppCompatActivity { String url = "http://guolin.tech/book.png"; ImageView image; ProgressDialog progressDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); image = (ImageView) findViewById(R.id.image); progressDialog = new ProgressDialog(this); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setMessage("加载中"); } public void loadImage(View view) { ProgressInterceptor.addListener(url, new ProgressListener() { @Override public void onProgress(int progress) { progressDialog.setProgress(progress); } }); Glide.with(this) .load(url) .diskCacheStrategy(DiskCacheStrategy.NONE) .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) .into(new GlideDrawableImageViewTarget(image) { @Override public void onLoadStarted(Drawable placeholder) { super.onLoadStarted(placeholder); progressDialog.show(); } @Override public void onResourceReady(GlideDrawable resource, GlideAnimation animation) { super.onResourceReady(resource, animation); progressDialog.dismiss(); ProgressInterceptor.removeListener(url); } }); }}
在GlideDrawableImageViewTarget中添加进度显示逻辑
确保在图片加载开始和完成时更新进度条:class GlideDrawableImageViewTarget extends GlideDrawableImageViewTarget { GlideDrawableImageViewTarget(ImageView view) { super(view); } @Override public void onLoadStarted(Drawable placeholder) { super.onLoadStarted(placeholder); progressDialog.show(); } @override public void onResourceReady(GlideDrawable resource, GlideAnimation animation) { super.onResourceReady(resource, animation); progressDialog.dismiss(); ProgressInterceptor.removeListener(url); }}
五、测试与验证
运行应用程序
在 Android Studio 中运行应用程序,点击Load Image
按钮加载图片。 观察清单
通过logcat
工具观察下载进度信息,确保进度监听功能正常工作。 测试不同图片类型
尝试加载不同大小和类型的图片(如GIF图),验证进度计算和显示的准确性。优化UI布局
为进度条添加更多自定义样式,如颜色、动画效果,以提升用户体验。六、总结
通过以上步骤,我们成功实现了Glide的下载进度监听功能。关键点包括替换Glide的HTTP通讯组件为OkHttp,利用OkHttp的强大拦截器机制实现进度监听,并通过自定义组件集成进度显示到用户界面。这种方法确保了下载进度能够实时反馈给用户,提升用户体验。
发表评论
最新留言
留言是一种美德,欢迎回访!
[***.207.175.100]2025年04月14日 05时58分38秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
vcenter访问报503错误处理
2019-03-12
项目计划甘特图绘制说明
2019-03-12
1009. clion调试段错误
2019-03-12
C/C++:线性表之顺序表
2019-03-12
嵌入式系统试题库(CSU)
2019-03-12
图神经网络7日打卡营学习心得
2019-03-12
electronJS 开发linux App
2019-03-12
MbedOS 设备中的模数转换(ADC)
2019-03-12
【vue】setInterval的嵌套实例
2019-03-12
【SpringBoot】如何配置热部署
2019-03-12
【rabbitMQ】04 如何实现高可用?
2019-03-12
【自考】之信息资源管理(一)
2019-03-12
C# 文本框限制大全
2019-03-12
setup facatory9.0打包详细教程(含静默安装和卸载)
2019-03-12
ionic4 路由跳转传值
2019-03-12
CSDN 怎么写出好看的博客
2019-03-12
pwn题shellcode收集
2019-03-12
python中的序列化
2019-03-12