androidglide加载不出(Android性能优化Glide巨图加载原理分析)
Glide 是目前非常流行的图片加载第三方开源库,而且功能极其强大,内部代码复杂程度也极其大。
Glide是纯Java写的Android端开源图片加载库,能够帮助我们下载、缓存、展示多种格式图片,也包括GIF格式 。
特点:- (1)使用简单
- (2)可配置度高,自适应程度高
- (3)支持常见图片格式 Jpg png gif webp
- (4)支持多种数据源 网络、本地、资源、Assets 等
- (5)高效缓存策略 支持Memory和Disk图片缓存 默认Bitmap格式采用RGB_565内存使用至少减少一半
- (6)生命周期集成 根据Activity/Fragment生命周期自动管理请求
- (7)高效处理Bitmap 使用Bitmap Pool使Bitmap复用,主动调用recycle回收需要回收的Bitmap,减小系统回收压力
- Android的内存申请几乎都在new的时候发生,而new较大对象(比如Bitmap时),更加容易触发GC_FOR_ALLOW。所以Glide尽量的复用资源来防止不必要的GC_FOR_ALLOC引起卡顿。
- 最显著的内存复用就是内存LruResourceCache(第一次从网络或者磁盘上读取到Resource时,并不会保存到LruCache当中,当Resource被release时,也就是View不在需要此Resource时,才会进入LruCache当中)
- 还有BitmapPool(Glide会尽量用图片池来获取到可以复用的图片,获取不到才会new,而当LruCache触发Evicted时会把从LruCache中淘汰下来的Bitmap回收,也会把transform时用到的中间Bitmap加以复用及回收)
- 4.4以前是Bitmap复用必须长宽相等才可以复用
- 4.4及以后是Size>=所需就可以复用,只不过需要调用reconfigure来调整尺寸
- Glide用AttributeStategy和SizeStrategy来实现两种策略
- 图片池在收到传来的Bitmap之后,通过长宽或者Size来从KeyPool中获取Key(对象复用到了极致,连Key都用到了Pool),然后再每个Key对应一个双向链表结构来存储。每个Key下可能有很多个待用Bitmap
- 取出后要减少图片池中记录的当前Size等,并对Bitmap进行eraseColor(Color.TRANSPAENT)操作确保可用
- Glide.with(context)创建RequestManager
- RequestManager负责管理当前context的所有Request
- Context可以传Fragment、Activity或者其他Context,当传Fragment、Activity时,当前页面对应的Activity的生命周期可以被RequestManager监控到,从而可以控制Request的pause、resume、clear。这其中采用的监控方法就是在当前activity中添加一个没有view的fragment,这样在activity发生onStart onStop onDestroy的时候,会触发此fragment的onStart onStop onDestroy。
- RequestManager用来跟踪众多当前页面的Request的是RequestTracker类,用弱引用来保存运行中的Request,用强引用来保存暂停需要恢复的Request。
2.Glide.with(context).load(url)创建需要的Request
- 通常是DrawableTypeRequest,后面可以添加transform、fitCenter、animate、placeholder、error、override、skipMemoryCache、signature等等
- 如果需要进行Resource的转化比如转化为Byte数组等需要,可以加asBitmap来更改为BitmapTypeRequest
- Request是Glide加载图片的执行单位
3.Glide.with(context).load(url).into(imageview)
- 在Request的into方法中会调用Request的begin方法开始执行
- 在正式生成EngineJob放入Engine中执行之前,如果并没有事先调用override(width, height)来指定所需要宽高,Glide则会尝试去获取imageview的宽和高,如果当前imageview并没有初始化完毕取不到高宽,Glide会通过view的ViewTreeObserver来等View初始化完毕之后再获取宽高再进行下一步
- GlideBuilder在初始化Glide时,会生成一个执行机Engine
- Engine中包含LruCache缓存及一个当前正在使用的active资源Cache(弱引用)
- activeCache辅助LruCache,当Resource从LruCache中取出使用时,会从LruCache中remove并进入activeCache当中
- Cache优先级LruCache>activeCache
- Engine在初始化时要传入两个ExecutorService,即会有两个线程池,一个用来从DiskCache获取resource,另一个用来从Source中获取(通常是下载)
- 线程的封装单位是EngineJob,有两个顺序状态,先是CacheState,在此状态先进入DiskCacheService中执行获取,如果没找到则进入SourceState,进到SourceService中执行下载
1. Glide.with(Context context).load(Strint url).into(ImageView imageView);
1. // 加载本地图片
2. File file = new File(getExternalCacheDir() "/image.jpg");
3. Glide.with(this).load(file).into(imageView);
4. // 加载应用资源
5. int resource = R.drawable.image;
6. Glide.with(this).load(resource).into(imageView);
7. // 加载二进制流
8. byte[] image = getImageBytes();
9. Glide.with(this).load(image).into(imageView);
10. // 加载Uri对象
11. Uri imageUri = getImageUri();
12. Glide.with(this).load(imageUri).into(imageView);
1. Glide.with(this).load(url).placeholder(R.drawable.loading).into(imageView);
占位图目的为在目的图片还未加载出来的时候,提前展示给用户的一张图片;
4、加载失败 放置占位符
1. Glide.with(this).load(url).placeholder(R.drawable.loading).error(R.drawable.error)
2. .diskCacheStrategy(DiskCacheStrategy.NONE)//关闭Glide的硬盘缓存机制
3. .into(imageView);
4. //DiskCacheStrategy.NONE:表示不缓存任何内容。
5. //DiskCacheStrategy.SOURCE:表示只缓存原始图片。
6. //DiskCacheStrategy.RESULT:表示只缓存转换过后的图片(默认选项)。
7. //DiskCacheStrategy.ALL :表示既缓存原始图片,也缓存转换过后的图片。
1. Glide.with(this)
2. .load(url)
3. .asBitmap()//只加载静态图片,如果是git图片则只加载第一帧。
4. .placeholder(R.drawable.loading)
5. .error(R.drawable.error)
6. .diskCacheStrategy(DiskCacheStrategy.NONE)
7. .into(imageView);
1. Glide.with(this)
2. .load(url)
3. .asGif()//加载动态图片,若现有图片为非gif图片,则直接加载错误占位图。
4. .placeholder(R.drawable.loading)
5. .error(R.drawable.error)
6. .diskCacheStrategy(DiskCacheStrategy.NONE)
7. .into(imageView);
1. Glide.with(this)
2. .load(url)
3. .placeholder(R.drawable.loading)
4. .error(R.drawable.error)
5. .diskCacheStrategy(DiskCacheStrategy.NONE)
6. .override(100, 100)//指定图片大小
7. .into(imageView);
1. Glide.with(this)
2. .load(url)
3. .skipMemoryCache(true) //传入参数为false时,则关闭内存缓存。
4. .into(imageView);
1. Glide.with(this)
2. .load(url)
3. .diskCacheStrategy(DiskCacheStrategy.NONE) //关闭硬盘缓存操作
4. .into(imageView);
5. //其他参数表示:
6. //DiskCacheStrategy.NONE:表示不缓存任何内容。
7. //DiskCacheStrategy.SOURCE:表示只缓存原始图片。
8. //DiskCacheStrategy.RESULT:表示只缓存转换过后的图片(默认选项)。
9. //DiskCacheStrategy.ALL :表示既缓存原始图片,也缓存转换过后的图片。
1. public class MyGlideUrl extends GlideUrl {
2. private String mUrl;
3. public MyGlideUrl(String url) {
4. • super(url);
5. • mUrl = url;
6. }
7. @Override
8. public String getCacheKey() {
9. • return mUrl.replace(findTokenParam(), "");
10. }
11. private String findTokenParam() {
12. • String tokenParam = "";
13. • int tokenKeyIndex = mUrl.indexOf("?token=") >= 0 ? mUrl.indexOf("?token=") : mUrl.indexOf("&token=");
14. • if (tokenKeyIndex != -1) {
15. • int nextAndIndex = mUrl.indexOf("&", tokenKeyIndex 1);
16. • if (nextAndIndex != -1) {
17. • tokenParam = mUrl.substring(tokenKeyIndex 1, nextAndIndex 1);
18. • } else {
19. • tokenParam = mUrl.substring(tokenKeyIndex);
20. • }
21. • }
22. • return tokenParam;
23. }
24. }
然后加载图片的方式为:
1. Glide.with(this)
2. .load(new MyGlideUrl(url))
3. .into(imageView);
(1)、拿到图片实例
1. //1、通过自己构造 target 可以获取到图片实例
2. SimpleTarget<GlideDrawable> simpleTarget = new SimpleTarget<GlideDrawable>() {
3. @Override
4. public void onResourceReady(GlideDrawable resource, GlideAnimation glideAnimation) {
5. • imageView.setImageDrawable(resource);
6. }
7. };
8. //2、将图片实例记载到指定的imageview上,也可以做其他的事情
9. public void loadImage(View view) {
10. String url = "http://cn.bing.com/az/hprichbg/rb/TOAD_ZH-CN7336795473_1920x1080.jpg";
11. Glide.with(this)
12. • .load(url)
13. • .into(simpleTarget);
14. }
(2)、将图片加载到任何位置
1. /*
2. *将图片加载为控件背景
3. */
4. public class MyLayout extends LinearLayout {
5. private ViewTarget<MyLayout, GlideDrawable> viewTarget;
6. public MyLayout(Context context, AttributeSet attrs) {
7. • super(context, attrs);
8. • viewTarget = new ViewTarget<MyLayout, GlideDrawable>(this) {
9. • @Override
10. • public void onResourceReady(GlideDrawable resource, GlideAnimation glideAnimation) {
11. • MyLayout myLayout = getView();
12. • myLayout.setImageAsBackground(resource);
13. • }
14. • };
15. }
16. public ViewTarget<MyLayout, GlideDrawable> getTarget() {
17. • return viewTarget;
18. }
19. public void setImageAsBackground(GlideDrawable resource) {
20. • setBackground(resource);
21. }
22. }
23. //引用图片到指定控件作为背景
24. public class MainActivity extends AppCompatActivity {
25. MyLayout myLayout;
26. @Override
27. protected void onCreate(Bundle savedInstanceState) {
28. • super.onCreate(savedInstanceState);
29. • setContentView(R.layout.activity_main);
30. • myLayout = (MyLayout) findViewById(R.id.background);
31. }
32. public void loadImage(View view) {
33. • String url = "http://cn.bing.com/az/hprichbg/rb/TOAD_ZH-CN7336795473_1920x1080.jpg";
34. • Glide.with(this)
35. • .load(url)
36. • .into(myLayout.getTarget());
37. }
38. }
1. //a、预加载代码
2. Glide.with(this)
3. .load(url)
4. .diskCacheStrategy(DiskCacheStrategy.SOURCE)
5. .preload();
6. //preload() 有两种重载
7. // 1、带有参数的重载,参数作用是设置预加载的图片大小;
8. //2、不带参数的表示加载的图片为原始尺寸;
9. //b、使用预加载的图片
10. Glide.with(this)
11. .load(url)
12. .diskCacheStrategy(DiskCacheStrategy.SOURCE)
13. .into(imageView);
Glide 是目前非常流行的图片加载第三方开源库,而且功能极其强大,内部代码复杂程度也极其大。经过一番心理斗争决定还是要好好学习Glide的部分源码设计。关于更多 Glide学习,我这里推荐网易高级攻城狮整理的《铺路架构师学习手册》,里面内容(100w字图解析 实战笔记)。加油Android人,不学永远在一个阶梯。私信:“手册”获取哦!
【私信:“手册”领取】大厂架构深度讲解手册
,免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com