使用图片加载框架的意义是什么呢?明明自己就可以使用网络请求从任何地方请求一张图片下来,为什么还要使用图片加载框架来加载图片?
一个简单的例子,在一个listView中每个item都有自己的图片要请求显示,且滑动出屏幕的item会被回收,在这种需求下,图片加载要考虑的就不止是单纯的网络请求和ui显示,还要有缓存、线程调度、资源回收、内存占用等问题,处理不好便会十分卡顿,稍不注意就是oom。
而图片加载框架,就是将多级缓存、异步线程调度、图片压缩等都做好了封装,使用者不需再关注内存占用、oom、网络请求等问题,可以将更多的精力都放在业务逻辑上,图片加载只用一行代码就给你完美的处理好,本次就针对图片加载框架Picasso进行一下解析。
使用
像如今盛行的大部分框架一样,源码暂且不谈,使用绝对要简便至上,一般的需求只需要如下一行代码:
|
|
with()方法中传入上下文context,load方法里可以传入本地文件、指向本地资源文件的R文件地址、url字符串、uri对象四种参数,into参数传入要加载图片的控件对象。
一行代码下来,运行起APP,就可以看到图片加载到了控件上,当然Picasso所做的事不止于此,它背后已经默默为你开了线程池、初始化好了缓存、做了图片压缩等等工作,这些后面详细分析。
继续回到使用上,前面说的那一行代码足以解决大部分需求,还有一部分可能会使用到的需求Picasso也考虑的很全面,可以看到load方法返回了一个RequestCreator对象,而在RequestCreator类中,Picasso开发者已经为我们封装好了所有可能用到的方法:
placeholder方法
这个方法可以用来在加载图片而图片还没有加载出来的时候显示一张占位图,使用户知道当前图片还在加载,不至于出现一片空白这种糟糕的用户体验。它有两个互相重载的方法,一个参数可以传入int类型的资源id,另一个参数是Drawable类型的资源对象。
使用方法也很简单,因为是RequestCreator类中的方法,所以只需要在之前的一行代码中在load之后、into之前调用即可。1Picasso.with(GlideTest.this).load(R.mipmap.ic_launcher).placeholder(R.mipmap.ic_launcher_round).into(img);error方法
设置请求图片出错的时候显示的图片,使用户知道图片加载错误了,也是有两个重载方法,分别可以传入资源id和drawable对象,用法与placeholder差不多,不再赘述。tag方法
用于为当前请求分配标签,用于统一管理相关的请求,参数是一个object对象,可以传入任意Object的子类。与这个方法有关的有Picasso类中的cancelTag(Object)、pauseTag(Object)、resumeTag(Object),分别用于对设置了对应tag的请求进行取消、暂停、重新启动操作。
适用这个方法的典型情景是,在列表视图中,如果快速进行滑动,则完全可以在滑动的时候暂停所有网络请求,在停止滑动的时候再次开始请求,实现这种需求的方法就是利用同一个tag在适当的地方调用resumeTag和pauseTag。
示例如下:12345678910111213141516171819202122//adapter中Picasso.with(parent.getContext()).load(paths.get(position)).fit().tag("item").into(holder.img);//activity中list.setOnScrollListener(new AbsListView.OnScrollListener() {public void onScrollStateChanged(AbsListView view, int scrollState) {switch (scrollState){case SCROLL_STATE_FLING:Picasso.with(GlideTest.this).pauseTag("item");break;case SCROLL_STATE_IDLE:Picasso.with(GlideTest.this).resumeTag("item");break;}}public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}});fit方法
在源码中这个方法只是将deferred的值改为true,而这个值为true的意义是使图片根据ImageView的大小充满整个view,不考虑比例,可能导致图片被拉伸或缩小。要注意的是,fit方法只能用在imageView上,且应用fit的imageView不能为wrapcontent,很好理解,毕竟fit要测量好宽高才能加载图片。
上面adapter中的使用就用到了fit方法12Picasso.with(parent.getContext()).load(paths.get(position)).fit().tag("item").into(holder.img);直观的看一下不使用fit和使用fit的区别
resizeDimen方法
作用就是根据传入的两个参数设置图片的宽高,这里两个参数是两个资源id,与之有关联的是resize方法,可以直接传入两个int值进行设置,resizeDimen方法内部最后也是调用了resize方法。使用方法还是跟在load方法之后调用即可,但是需要注意一点,该方法和resize方法都不能与fit方法一起使用,否则会抛出错误导致程序崩溃。
这个不难理解,fit方法使图片自己适应到整个ImageView的宽高,resize和resizeDimen又是告诉Picasso你想要显示一个具体宽高的图片,这种前后矛盾的命令,不要说程序会崩溃了,换你你也崩溃。centerInside¢erCrop方法
熟悉ImageView方法的同学应该会觉得眼熟,这两个方法在ImageView中也有,在这里的作用和在ImageView中的作用差别不大,centerCrop方法以将控件填满为最终目的,会调整图片的尺寸,使宽高都扩展到足以触碰到ImageView的边界,然后将边界外的部分裁剪掉,所以图片的显示是不完全的;centerInside则是以把图片完整的放到控件内为目的,如果宽高比控件大,则缩放至刚好可以放在控件内的程度,比控件小就直接显示。
这两个方法是必须跟在拿到具体宽高的方法后的,即必须跟在resize的两个方法或fit方法后,不然会抛异常。onlyScaleDown方法
设置在只有原始图片比目标size大的时候才调用resize方法,即此方法只能在resize方法调用后调用。rotate方法
设置图片旋转,有两个重载方法,一个传入一个旋转角度的float值degree,另一个传入degree和一个旋转中心点的x和y坐标。priority方法
传入priority枚举类的对象,设定当前请求的优先级,优先级高的先请求。transform方法
传入一个自定义Transformation对象,可以在load之后、into之前对图片做很多转换处理,能想到的需求比如设置圆角图片、高斯模糊等都可以通过传入对应的Transformation实现。skipMemoryCache方法
跳过内存缓存,内部调用了memoryPolicy方法,作用是不再让Picasso将请求到的图片缓存到内存,而是直接缓存到磁盘上。networkPolicy方法
可以理解为设置网络策略的方法,参数传入枚举NetworkPolicy的值,枚举类型有三个:123456789101112/** Skips checking the disk cache and forces loading through the network. */NO_CACHE(1 << 0),/*** Skips storing the result into the disk cache.* <p>* <em>Note</em>: At this time this is only supported if you are using OkHttp.*/NO_STORE(1 << 1),/** Forces the request through the disk cache only, skipping network. */OFFLINE(1 << 2);NO_CACHE表示处理请求的时候跳过磁盘缓存,即不管磁盘中有没有这次请求的缓存,都会从网络上重新请求一个下来;
NO_STORE表示请求成功后,不将请求结果缓存到磁盘中,但这个只对okhttp有效;
OFFLINE表示离线状态,不管磁盘中有没有缓存,设置这个状态后,都不会再从网络请求数据,而是直接从缓存中获取结果,不管缓存中能否获取到结果。fetch()方法
用来预加载一张图片,可以在获取到ImageView或者target之前就将图片缓存下来。它还有一个重载方法是有一个callback参数,可以用来回调,然而这个 callback的回调方法是没有参数的,大概只是想用来告诉你这个请求是请求成功了还是失败了吧。。。
以上的方法基本涵盖了Picasso的各种用法,下篇会从源码上对Picasso进行分析。