Picasso学习

来源:互联网 发布:陕西大数据集团胡刚 编辑:程序博客网 时间:2024/06/09 16:57

简介:

Picasso是Square公司开源的一个Android图形缓存库。可以实现图片下载和缓存功能。

文档地址:http://square.github.io/picasso/2.x/picasso/;

下载地址:http://square.github.io/picasso/#download

特点:

1.加载载网络或本地图片并自动缓存处理;

2.链式调用;

3.图形转换操作,如变换大小,旋转等,提供了接口来让用户可以自定义转换操作;

4.在Adapter中回收和取消当前的下载功能;

 

与Universal-ImageLoader库对比:

1.都有高效的网络图片下载和缓存性能;
2.Universal-ImageLoader功能多,灵活使用配置;
3.Picasso使用复杂的图片压缩转换来尽可能的减少内存消耗;
4.在Adapter中需要取消已经不在视野范围的ImageView图片资源的加载,否则会导致图片错位,Picasso已经解决了这个问题;

用法:

(1)Picasso.with(context).load(url).into(imageView);(2)Picasso.with(context).load(url).resize(50,50).centerCrop().placehold er(holderUrl).error(errorUrl).into(imageView);
Resize(x,y):重新设置图片尺寸;
centerCrop():scaleType设置为centerCrop;
rotate(degrees):旋转图片;

除了加载网络图片,picasso还支持加载Resources,assets, files, content providers中的本地资源文件

流程图:


流程总结:当执行Picasso.with(context).load(url).into(imagevi)时,会首先构造Picasso实例,然后会根据url创建请求(Request,Action),将请求交给Dispatcher,Dispatcher再在子线程对请求任务进行调度,将请求任务交给线程池(ExecutorService),执行完毕后,将结果传给主线程的handler,最后在主线程中将图片设置到ImageView上。

关键类分析:



Picasso:

负责图片下载、转换和缓存的管理。

Picasso.with(context)采用单例模式+双重锁定模式创建Picasso实例:

public staticPicassowith(Context context) {
 
if (singleton==null) {
   
synchronized (Picasso.class) {
     
if (singleton==null) {
       
singleton =newBuilder(context).build();
     
}
   
}
  }
  return singleton;
}

 

Request::

Request表示一个任务请求,记录所有对图形的操作,供之后图形的创建使用(如resize,rotate)。还可以实现接口Transformation,进行自定义图形变换。

RequstCreator:

       负责生成Request对象,into()方法是加载图片的入口。

public voidinto(Target target){
 
long started = System.nanoTime();
 
checkMain();//检查是否是主线程

 
if (target ==null) {
   
throw new IllegalArgumentException("Target must not be null.");
 
}
 
if (deferred) {
   
throw new IllegalStateException("Fit cannot be used with a Target.");
 
}
 
//判断ImageView是否正确
 
if (!data.hasImage()) {
   
picasso.cancelRequest(target);
   
target.onPrepareLoad(setPlaceholder? getPlaceholderDrawable() :null);
   
return;
  }
 
//创建Request对象
 
Request request = createRequest(started);
 
String requestKey = createKey(request);
 
//判断缓存是否有图片
 
if (shouldReadFromMemoryCache(memoryPolicy)) {
   
Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
   
if (bitmap != null) {
     
picasso.cancelRequest(target);
     
target.onBitmapLoaded(bitmap,MEMORY);
     
return;
    }
 
}

  target.onPrepareLoad(setPlaceholder ?getPlaceholderDrawable() :null);

 
Action action =
     
new TargetAction(picasso,target,request,memoryPolicy,networkPolicy,errorDrawable,
         
requestKey,tag,errorResId);
 
picasso.enqueueAndSubmit(action);//提交请求任务Action
}

 

Action:

Action代表一个具体的加载任务,主要用于图片加载后的结果回调。

ImageViewAction实现了Action的两个抽象方法:complete()和error()。Complete()将bitmap设置给imageView,并回调callback.onSuccess();error()将errorDrawable设置给ImageView,并回调callback.onError()。

public voidcomplete(Bitmap result,Picasso.LoadedFromfrom) {
 

  //bitmap加載到ImageView
 
Context context = picasso.context;
 
boolean indicatorsEnabled = picasso.indicatorsEnabled;
 
PicassoDrawable.setBitmap(target,context,result,from,noFade,indicatorsEnabled);
 
//回調callback.onSuccess()
 
if (callback!=null) {
   
callback.onSuccess();
 
}
}

Action有个需要关注的点,那就是WeakReference target,它持有的是Target(比如ImageView ..)的弱引用,这样可以保证加载时间很长的情况下也不会影响到Target的回收了。

BitmapHunter:

实现了Runnable接口,通过PicassoExecutorService.submit(Runnable)把bitmapHunter对象添加到工作线程任务队列,获取并上传目标图片(dispatcher.dispatchComplete(this))。

Hunt(){

//加载图片
data.networkPolicy=retryCount==0? NetworkPolicy.OFFLINE.index:networkPolicy;
RequestHandler.Result result = requestHandler.load(data,networkPolicy,picasso.byteArrayPool);

}

假设从网络取值,查看NetworkRequestHandler.load():

public Result load(Request request, intnetworkPolicy,ByteArrayPool byteArrayPool) throwsIOException {
 
//利用downloader下载图片数据,downloader是创建Dispatcher时传进来的
 
Response response = downloader.load(request.uri,request.networkPolicy);
 
if (response == null) {
   
return null;
 
}
 
//判断是从缓存取还是从网络取
 
Picasso.LoadedFrom loadedFrom = response.cached?DISK:NETWORK;

 
Bitmap bitmap = response.getBitmap();
 
if (bitmap != null) {
   
return new Result(bitmap,loadedFrom);
 
}
 
//如果是从网络返回的,那么拿到的是流对象
 
InputStream is = response.getInputStream();
 
if (is == null) {
   
return null;
 
}
 
// Sometimes response content length is zero when requests are beingreplayed. Haven't found
 
// root cause to this but retrying therequest seems safe to do so.
  if (loadedFrom ==DISK&&response.getContentLength() ==0) {
   
Utils.closeQuietly(is);
   
throw new ContentLengthException("Receivedresponse with 0 content-length header.");
 
}
 
if (loadedFrom ==NETWORK&&response.getContentLength() >0) {
   
stats.dispatchDownloadFinished(response.getContentLength());
 
}
 
MarkableInputStream markStream = new MarkableInputStream(is);
 
long mark = markStream.savePosition(65536);//TODO fix thiscrap.
 
int orientation =newImageHeaderParser(markStream,byteArrayPool).getOrientation();
 
markStream.reset(mark);
 
//将结果封装返回
 
return new Result(null,markStream,loadedFrom,orientation);
}

 

Dispatcher:

是整个图片加载过程的任务调度器。外部调用dispatchXXX()方法,然后通过handler将请求转换为调用对于的performXXX()。

void performSubmit(Action action, booleandismissFailed){
 

 
//生成bitmapHunter,其中遍历requestHandlers,通过requestHandler.canHandleRequest(request)匹配合适的RequestHandler子类
 
hunter = forRequest(action.getPicasso(), this,cache,stats,action);
 
//hunter任务加入到工作线程任务栈,并获取future返回
 
hunter.future=service.submit(hunter);
 
hunterMap.put(action.getKey(),hunter);
 

}

 

Cache:

实现图片的缓存。LruCache实现了Cache接口,存储的结构采用了LinkedHashMap,这种map内部实现了lru算法(Least Recently Used 近期最少使用算法)。主要是set()和get()方法,图片下载完成后,在dispatcher.performComplete()会调用set()方法。而在requestCreator.into(),bitmapHunter.hunt()会通过shouldReadFromMemoryCache(memoryPolicy)检查是否可以从缓存获取图片,如果可以则调用get()方法。

附:

Tansformation 的实现例子,实现圆形图片显示。

import android.graphics.Bitmap;import android.graphics.BitmapShader;import android.graphics.Canvas;import android.graphics.Paint;import com.squareup.picasso.Transformation;public class CircleTransform implements Transformation {    @Override    public Bitmap transform(Bitmap source) {        int size = Math.min(source.getWidth(), source.getHeight());        int x = (source.getWidth() - size) / 2;        int y = (source.getHeight() - size) / 2;        Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);        if (squaredBitmap != source) {            source.recycle();        }        Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());        Canvas canvas = new Canvas(bitmap);        Paint paint = new Paint();        BitmapShader shader = new BitmapShader(squaredBitmap,                BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);        paint.setShader(shader);        paint.setAntiAlias(true);        float r = size / 2f;        canvas.drawCircle(r, r, r, paint);        squaredBitmap.recycle();        return bitmap;    }    @Override    public String key() {        return "circle";    }}

参考文档:http://www.2cto.com/kf/201511/451087.html
1 0
原创粉丝点击