图片加载库 Picasso 的使用

来源:互联网 发布:php注册页面代码 编辑:程序博客网 时间:2024/05/17 03:48

Picasso

背景:picasso是Square公司出的一款图片加载框架,能够解决我们在Android开发中加载图片时遇到的诸多问题,比如OOM,图片错位等,问题主要集中在加载图片列表时,因为单张图片加载谁都会写。如果我们想在ListView或者GridView或者RecyclerView中加载图片墙,那么这个时候对原图片的二次处理就显得非常重要了,否则就会出现我们上文说的OOM或者图片错位等。不过,如果你使用了Picasso来加载图片的话,那么所有问题都会变得很简单。

基本使用

  • 加载网络图片
Picasso.with(this).load("http://n.sinaimg.cn/translate/20160819/9BpA-fxvcsrn8627957.jpg").into(iv); 
  • 对网络图片裁剪
Picasso.with(this).load("http://n.sinaimg.cn/translate/20160819/9BpA-fxvcsrn8627957.jpg")                  .resize(200,200)                  .into(iv);//注意这里的200表示200px,如果你想在resize时指定dp,可以使用如下方法Picasso.with(this).load("http://n.sinaimg.cn/translate/20160819/9BpA-fxvcsrn8627957.jpg")                  .resizeDimen(R.dimen.iv_width,R.dimen.iv_height)                  .into(iv); 
  • 缩放模式
Picasso.with(this).load("http://n.sinaimg.cn/translate/20160819/9BpA-fxvcsrn8627957.jpg")          .resizeDimen(R.dimen.iv_width,R.dimen.iv_height)          .centerCrop()          .into(iv); 
  • 默认图
Picasso.with(this).load("http://n.sinaimg.cn/translate/20160819/9BpA-fxvcsrn8627957.jpg")                  //占位图,图片加载出来之前显示的默认图片                  .placeholder(R.mipmap.ic_launcher)                  //错误图,图片加载出错时显示的图片                  .error(R.mipmap.ic_launcher)                  .into(iv); 
  • 裁剪,高斯模糊
Picasso.with(this).load("http://n.sinaimg.cn/translate/20160819/9BpA-fxvcsrn8627957.jpg")                 .transform(transformation)                 .into(iv); 
  • 查看图片从哪里加载
Picasso picasso = Picasso.with(this);         //开启指示器         picasso.setIndicatorsEnabled(true);         picasso.load("http://n.sinaimg.cn/translate/20160819/9BpA-fxvcsrn8627957.jpg")                 .into(iv); 

缓存

默认缓存位置:data/data/packagename/cache
缓存方式:Disk 和 Memory
缓存策略:
NO_CACHE:表示处理请求的时候跳过检查内存缓存
NO_STORE: 表示请求成功之后,不将最终的结果存到内存

with(this).load(URL)          .placeholder(R.drawable.default_bg)          .error(R.drawable.error_iamge)              .memoryPolicy(MemoryPolicy.NO_CACHE,MemoryPolicy.NO_STORE) //禁止内存缓存                        .into(mBlurImage);

磁盘缓存:
NO_CACHE: 表示处理请求的时候跳过处理磁盘缓存
NO_STORE: 表示请求成功后,不将结果缓存到Disk,但是这个只对OkHttp有效。
OFFLINE: 这个就跟 上面两个不一样了,如果networkPolicy方法用的是这个参数,那么
Picasso会强制这次请求从缓存中获取结果,不会发起网络请求,不管缓存中能否获取到结果。

 with(this).load(URL)           .placeholder(R.drawable.default_bg)           .error(R.drawable.error_iamge)           .memoryPolicy(MemoryPolicy.NO_CACHE,MemoryPolicy.NO_STORE)//跳过内存缓存           .networkPolicy(NetworkPolicy.NO_CACHE)//跳过磁盘缓存           .into(mBlurImage);

默认缓存位置:

static Downloader createDefaultDownloader(Context context) {    try {              Class.forName("com.squareup.okhttp.OkHttpClient");              return OkHttpLoaderCreator.create(context);        } catch (ClassNotFoundException ignored) {        }        return new UrlConnectionDownloader(context);  }

自定义下载器

Picasso picasso = new Picasso.Builder(this)                  .downloader(new OkHttp3Downloader(this.getExternalCacheDir()))                  .build();          Picasso.setSingletonInstance(picasso);          picasso.load("http://n.sinaimg.cn/translate/20160819/9BpA-fxvcsrn8627957.jpg").into(iv);

Tag管理请求

cancelTag(Object tag) 取消设置了给定tag的所有请求
pauseTag(Object tag) 暂停设置了给定tag 的所有请求
resumeTag(Object tag) resume 被暂停的给定tag的所有请求

Adapter中添加如下代码:

Picasso.with(this).load(mData.get(position))                .placeholder(R.drawable.default_bg)                .error(R.drawable.error_iamge)                .tag("PhotoTag")                .into(holder.mImageView);

Activity中为RecyclerView添加滑动监听

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {            @Override            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {                final Picasso picasso = Picasso.with(MainActivity.this);                if (newState == SCROLL_STATE_IDLE) {                    picasso.resumeTag("PhotoTag");                } else {                    picasso.pauseTag("PhotoTag");                }            }        });

Activity结束的时候,清除tag

 @Override    protected void onDestroy() {        super.onDestroy();        Picasso.with(this).cancelTag("PhotoTag");    }

线程池

PicassoExecutorService:默认3个线程
也可以自定义线程池

源码分析

通过Builder模式创建实例

1.Picasso.Builder build

/** Start building a new {@link Picasso} instance. */public Builder(Context context) {    if (context == null) {        throw new IllegalArgumentException("Context must not be null.");    }    this.context = context.getApplicationContext();}private Downloader downloader;private ExecutorService service;private Cache cache;private Listener listener;private RequestTransformer transformer;private List<RequestHandler> requestHandlers;private Bitmap.Config defaultBitmapConfig;/** Create the {@link Picasso} instance. */public Picasso build() {    Context context = this.context;    // 为这一系列变量进行默认初始化    // Downloader执行实际的下载业务,返回Response    if (downloader == null) {        downloader = Utils.createDefaultDownloader(context);    }    // 内存缓存,可以看到默认的是LruCache    if (cache == null) {        cache = new LruCache(context);    }    // 线程池,执行网络请求的地方    if (service == null) {        service = new PicassoExecutorService();    }    // request发送前进行处理    if (transformer == null) {        transformer = RequestTransformer.IDENTITY;    }    // 用以统计    Stats stats = new Stats(cache);    // 进行Request以及Response的转发    Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);    // 创建一个Picasso    return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,            defaultBitmapConfig, indicatorsEnabled, loggingEnabled);}

2. Picasso#load

public RequestCreator load(String path) {    if (path == null) {        return new RequestCreator(this, null, 0);    }    if (path.trim().length() == 0) {        throw new IllegalArgumentException("Path must not be empty.");    }    return load(Uri.parse(path));}public RequestCreator load(Uri uri) {    return new RequestCreator(this, uri, 0);}

这里创建一个RequestCreator

private final Picasso picasso;private final Request.Builder data;RequestCreator(Picasso picasso, Uri uri, int resourceId) {    if (picasso.shutdown) {        throw new IllegalStateException(                "Picasso instance already shut down. Cannot submit new requests.");    }    this.picasso = picasso;    this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);}

data对应创建一个Request的Builder,这个Request中封装了了相应的请求信息,传入了请求加载图片的URI,已经resourceId,以及默认显示图片的配置信息。
进而一般调用into将图片加载到相应的控件中。

RequestCreator#into

// RequestCreator.javapublic void into(ImageView target) {    into(target, null);}public void into(ImageView target, Callback callback) {    long started = System.nanoTime();    // 盘算是否是在主线程,如果不是则会抛出异常    checkMain();    if (target == null) {        throw new IllegalArgumentException("Target must not be null.");    }    // 判断reqeust是否合法,即存在URI或者对应的resId,否则会取消该请求    if (!data.hasImage()) {        picasso.cancelRequest(target);        if (setPlaceholder) {            setPlaceholder(target, getPlaceholderDrawable());        }        return;    }    // 判断是否需要延期执行    if (deferred) {        // 判断是否已经设置了宽高大小        if (data.hasSize()) {            throw new IllegalStateException("Fit cannot be used with resize.");        }        // 获取目标控件的宽高参数        int width = target.getWidth();        int height = target.getHeight();        // 表示当前控件并未加载到界面上(宽或高为0)        if (width == 0 || height == 0) {            if (setPlaceholder) {                setPlaceholder(target, getPlaceholderDrawable());            }            // 生成DeferredRequestCreator,加入相应队列进行处理            picasso.defer(target, new DeferredRequestCreator(this, target, callback));            return;        }        // 设置Request.Builder中的宽高参数大小        data.resize(width, height);    }    // 创建Request    Request request = createRequest(started);    // 获取request对应的key    String requestKey = createKey(request);    // 根据策略判断是够需要跳过读取MemoryCache    if (shouldReadFromMemoryCache(memoryPolicy)) { // 尝试从MemoryCache中获取Bitmap        // 根据Requeskey来获取相应的Bitmap        Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);        if (bitmap != null) {            // 如果从MemoryCache中获取到相应的bitmap,则取消request            picasso.cancelRequest(target);            // 设置图片            setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled);            if (picasso.loggingEnabled) {                log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY);            }            // 调用回调callback的onSuccess函数            if (callback != null) {                callback.onSuccess();            }            return;        }    }    // 如果从MemoryCache获取图片失败,或者根据缓存策略直接跳过读取MemoryCache,则设置默认图片    if (setPlaceholder) {        setPlaceholder(target, getPlaceholderDrawable());    }    // 创建ImageViewAction,Action里面包含了一次请求所需要的所有信息    Action action =            new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,                    errorDrawable, requestKey, tag, callback, noFade);    // 将action入队列    picasso.enqueueAndSubmit(action);}

附一张流程图:
Picasso构造流程图

相关文章:
http://blog.csdn.net/woliuyunyicai/article/details/51417839