《Android开源库》Picasso
1. 前言
最近項(xiàng)目開(kāi)發(fā)中使用到來(lái)Picasso,并且碰到了一個(gè)部分圖片無(wú)法加載的問(wèn)題,使用Glide可以正常加載,使用最新的Picasso3.0.0-SNAPSHOT版本也沒(méi)有問(wèn)題,最后使用Picasso自帶的異常監(jiān)聽(tīng)獲取堆棧,并且在Github中找到的同樣的問(wèn)題,具體查閱:
https://github.com/square/picasso/issues/1514
所以,想詳細(xì)的看看Picasso的詳細(xì)用法和master分支上的源代碼。
2. 基本介紹
Picasso 是Square 公司開(kāi)源的Android 端的圖片加載和緩存框架。圖片的加載是一個(gè)令人很頭疼的問(wèn)題,因?yàn)樯婕暗膬?nèi)容比較多,比如網(wǎng)絡(luò)請(qǐng)求,本地存儲(chǔ),圖片緩存,圖片回收等等,處理不好可能會(huì)出現(xiàn)圖片變形內(nèi)存泄漏等令開(kāi)發(fā)者焦頭爛額的問(wèn)題,但是Picasso幫我們做了很多事情,比如:
- 處理Adapter 中ImageView的回收和取消下載。
- 使用最小的內(nèi)存 來(lái)做復(fù)雜的圖片變換。比如高斯模糊,圓角、圓形等處理。
- 自動(dòng)幫我們緩存圖片。內(nèi)存和磁盤緩存
3. 基本使用
以Android Studio為開(kāi)發(fā)環(huán)境,以Gradle為構(gòu)建工具,其他的本文不做介紹。
3.1 添加依賴
compile 'com.squareup.picasso:picasso:2.5.2'3.2 混淆
-dontwarn com.squareup.okhttp.**3.3 加載圖片
/* 網(wǎng)絡(luò)圖片 */ Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);/* 圖片資源 */ Picasso.with(context).load(R.drawable.landing_screen).into(imageView1);/* 本地圖片*/ Picasso.with(context).load("file:///android_asset/DvpvklR.png").into(imageView2);/* 本地圖片文件 */ Picasso.with(context).load(new File(...)).into(imageView3);3.3.1 Picasso.with(Context context)
/*** The global default {@link Picasso} instance.* <p>* This instance is automatically initialized with defaults that are suitable to most* implementations.* <ul>* <li>LRU memory cache of 15% the available application RAM</li>* <li>Disk cache of 2% storage space up to 50MB but no less than 5MB. (Note: this is only* available on API 14+ <em>or</em> if you are using a standalone library that provides a disk* cache on all API levels like OkHttp)</li>* <li>Three download threads for disk and network access.</li>* </ul>* <p>* If these settings do not meet the requirements of your application you can construct your own* with full control over the configuration by using {@link Picasso.Builder} to create a* {@link Picasso} instance. You can either use this directly or by setting it as the global* instance with {@link #setSingletonInstance}.*/public static Picasso with(Context context) {if (singleton == null) {synchronized (Picasso.class) {if (singleton == null) {singleton = new Builder(context).build();}}}return singleton;}構(gòu)造一個(gè)默認(rèn)的Picasso單例,如果注釋中的一些基本配置需求無(wú)法滿足你,你可以使用Picasso.Builder來(lái)構(gòu)造自己的Picasso實(shí)例。
3.3.2 load()
很顯然,四個(gè)load方法,不同的入?yún)?#xff0c;相同類型的返回值。針對(duì)不同的圖片來(lái)源,執(zhí)行不同的加載方式。
每一個(gè)load()方法都是創(chuàng)建一個(gè)RequestCreator實(shí)例,load(File file)和load(String path)最后都是通過(guò)轉(zhuǎn)換成load(Uri uri)的方式實(shí)現(xiàn)加載。而RequestCreator的構(gòu)造方法中三個(gè)參數(shù),第一個(gè)是Picasso實(shí)例,一個(gè)是uri,一個(gè)是resourceId,通過(guò)后兩個(gè)參數(shù)覆蓋所有的加載場(chǎng)景。
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);}3.3.3 into()
RequestCreator中很多方法都是我們經(jīng)常會(huì)用到的。先看into()方法
可以看到5個(gè)into()方法,可以看到Picasso常用的是直接往ImageView,但是它的功能遠(yuǎn)遠(yuǎn)不止如此,我們可以通過(guò)實(shí)現(xiàn)Target接口來(lái)實(shí)現(xiàn)自定義的圖片處理,可以用來(lái)設(shè)背景,可以用來(lái)填充布局,可擴(kuò)展性很強(qiáng),也支持RemoteView。而我們常用的
public void into(ImageView target) {into(target, null);}轉(zhuǎn)到有Callback的執(zhí)行方法。我們可以通過(guò)使用帶有回調(diào)的into方法來(lái)執(zhí)行圖片加載成功或者失敗后的事件處理。
public interface Callback {void onSuccess();void onError();public static class EmptyCallback implements Callback {@Override public void onSuccess() {}@Override public void onError() {}} }看下public void into(ImageView target, Callback callback)這個(gè)方法:
以上就是圖片加載的主要過(guò)程。
4. 進(jìn)階用法(鏈?zhǔn)绞褂?
主要介紹一下Picasso的其他用法
4.1 noPlaceholder()
不設(shè)置占位圖片,不能于placeHolder同時(shí)使用
/*** Explicitly opt-out to having a placeholder set when calling {@code into}.* <p>* By default, Picasso will either set a supplied placeholder or clear the target* {@link ImageView} in order to ensure behavior in situations where views are recycled. This* method will prevent that behavior and retain any already set image.*/public RequestCreator noPlaceholder() {if (placeholderResId != 0) {throw new IllegalStateException("Placeholder resource already set.");}if (placeholderDrawable != null) {throw new IllegalStateException("Placeholder image already set.");}setPlaceholder = false;return this;}4.2 placeholder()
設(shè)置占位圖片
/*** A placeholder drawable to be used while the image is being loaded. If the requested image is* not immediately available in the memory cache then this resource will be set on the target* {@link ImageView}.*/public RequestCreator placeholder(int placeholderResId) {if (!setPlaceholder) {throw new IllegalStateException("Already explicitly declared as no placeholder.");}if (placeholderResId == 0) {throw new IllegalArgumentException("Placeholder image resource invalid.");}if (placeholderDrawable != null) {throw new IllegalStateException("Placeholder image already set.");}this.placeholderResId = placeholderResId;return this;}4.3 error()
設(shè)置加載出錯(cuò)時(shí)的圖片
/** An error drawable to be used if the request image could not be loaded. */public RequestCreator error(int errorResId) {if (errorResId == 0) {throw new IllegalArgumentException("Error image resource invalid.");}if (errorDrawable != null) {throw new IllegalStateException("Error image already set.");}this.errorResId = errorResId;return this;}/** An error drawable to be used if the request image could not be loaded. */public RequestCreator error(Drawable errorDrawable) {if (errorDrawable == null) {throw new IllegalArgumentException("Error image may not be null.");}if (errorResId != 0) {throw new IllegalStateException("Error image already set.");}this.errorDrawable = errorDrawable;return this;}4.4 tag()
設(shè)置tag,方便后續(xù)pause,cancel,或者resume。這個(gè)應(yīng)該用的比較少,有可能通過(guò)tag來(lái)cancel一下。
/*** Assign a tag to this request. Tags are an easy way to logically associate* related requests that can be managed together e.g. paused, resumed,* or canceled.* <p>* You can either use simple {@link String} tags or objects that naturally* define the scope of your requests within your app such as a* {@link android.content.Context}, an {@link android.app.Activity}, or a* {@link android.app.Fragment}.** <strong>WARNING:</strong>: Picasso will keep a reference to the tag for* as long as this tag is paused and/or has active requests. Look out for* potential leaks.** @see Picasso#cancelTag(Object)* @see Picasso#pauseTag(Object)* @see Picasso#resumeTag(Object)*/public RequestCreator tag(Object tag) {if (tag == null) {throw new IllegalArgumentException("Tag invalid.");}if (this.tag != null) {throw new IllegalStateException("Tag already set.");}this.tag = tag;return this;}4.5 fit() & unfit()
調(diào)整圖片大小來(lái)適配target的邊界,這個(gè)會(huì)導(dǎo)致圖片的加載過(guò)程在ImageView布局確定之后進(jìn)行。
/*** Attempt to resize the image to fit exactly into the target {@link ImageView}'s bounds. This* will result in delayed execution of the request until the {@link ImageView} has been laid out.* <p>* <em>Note:</em> This method works only when your target is an {@link ImageView}.*/public RequestCreator fit() {deferred = true;return this;}/** Internal use only. Used by {@link DeferredRequestCreator}. */RequestCreator unfit() {deferred = false;return this;}4.6 resizeDimen() & resize()
調(diào)整圖片大小。
/** Resize the image to the specified dimension size. */public RequestCreator resizeDimen(int targetWidthResId, int targetHeightResId) {Resources resources = picasso.context.getResources();int targetWidth = resources.getDimensionPixelSize(targetWidthResId);int targetHeight = resources.getDimensionPixelSize(targetHeightResId);return resize(targetWidth, targetHeight);}/** Resize the image to the specified size in pixels. */public RequestCreator resize(int targetWidth, int targetHeight) {data.resize(targetWidth, targetHeight);return this;}4.7 centerCrop() & centerInside()
centerCrop:充滿ImageView居中裁剪
centerInside: 完整顯示圖片但是可能無(wú)法充滿ImageView
4.8 onlyScaleDown()
當(dāng)調(diào)用了resize 方法重新設(shè)置圖片尺寸的時(shí)候,調(diào)用onlyScaleDown 方法,只有當(dāng)原始圖片的尺寸大于我們指定的尺寸時(shí),resize才起作用。
/*** Only resize an image if the original image size is bigger than the target size* specified by {@link #resize(int, int)}.*/public RequestCreator onlyScaleDown() {data.onlyScaleDown();return this;}4.9 rotate()
旋轉(zhuǎn)圖片角度,可指定旋轉(zhuǎn)中心點(diǎn)
/** Rotate the image by the specified degrees. */public RequestCreator rotate(float degrees) {data.rotate(degrees);return this;}/** Rotate the image by the specified degrees around a pivot point. */public RequestCreator rotate(float degrees, float pivotX, float pivotY) {data.rotate(degrees, pivotX, pivotY);return this;}4.10 config()
設(shè)置圖片Bitmap格式,如
ALPHA_8,ARGB_4444,ARGB_8888,HARDWARE,RGBA_F16,RGB_565等等。
4.11 stableKey()
設(shè)置固定Key
/*** Sets the stable key for this request to be used instead of the URI or resource ID when* caching. Two requests with the same value are considered to be for the same resource.*/public RequestCreator stableKey(String stableKey) {data.stableKey(stableKey);return this;}4.12 priority()
設(shè)置優(yōu)先級(jí),這個(gè)對(duì)圖片請(qǐng)求的執(zhí)行順序有影響,默認(rèn)的優(yōu)先級(jí)均為NORMAL
/*** Set the priority of this request.* <p>* This will affect the order in which the requests execute but does not guarantee it.* By default, all requests have {@link Priority#NORMAL} priority, except for* {@link #fetch()} requests, which have {@link Priority#LOW} priority by default.*/public RequestCreator priority(Priority priority) {data.priority(priority);return this;}4.13 transform()
添加自定義Transformation,方便執(zhí)行圖形轉(zhuǎn)換。
更多transformation請(qǐng)移步picasso-transformations
4.14 memoryPolicy()
指定memoryPolicy。NO_CACHE,NO_STORE
NO_CACHE:表示處理請(qǐng)求的時(shí)候跳過(guò)檢查內(nèi)存緩存
NO_STORE: 表示請(qǐng)求成功之后,結(jié)果不存到內(nèi)存。
4.15 networkPolicy()
指定NetworkPolicy。NO_CACHE,NO_STORE,OFFLINE
NO_CACHE: 表示處理請(qǐng)求的時(shí)候跳過(guò)處理磁盤緩存
NO_STORE: 表示請(qǐng)求成功后,結(jié)果不緩存到Disk。
OFFLINE: 強(qiáng)制這次請(qǐng)求從緩存中獲取結(jié)果,不會(huì)發(fā)起網(wǎng)絡(luò)請(qǐng)求,不管緩存中能否獲取到結(jié)果。
4.16 noFade()
去掉默認(rèn)的圖片加載過(guò)程中的漸入效果
/** Disable brief fade in of images loaded from the disk cache or network. */public RequestCreator noFade() {noFade = true;return this;}5. 其他用法
5.1 get()
同步方法,獲取Bitmap。所以不要在主線程執(zhí)行此操作
用法:
源碼實(shí)現(xiàn):
/*** Synchronously fulfill this request. Must not be called from the main thread.* <p>* <em>Note</em>: The result of this operation is not cached in memory because the underlying* {@link Cache} implementation is not guaranteed to be thread-safe.*/public Bitmap get() throws IOException {long started = System.nanoTime();checkNotMain();if (deferred) {throw new IllegalStateException("Fit cannot be used with get.");}if (!data.hasImage()) {return null;}Request finalData = createRequest(started);String key = createKey(finalData, new StringBuilder());Action action = new GetAction(picasso, finalData, memoryPolicy, networkPolicy, tag, key);return forRequest(picasso, picasso.dispatcher, picasso.cache, picasso.stats, action).hunt();}5.2 fetch()
毫無(wú)結(jié)果的獲取圖片,也沒(méi)有目標(biāo),也沒(méi)有返回bitmap,難道只是為了暖場(chǎng)?考慮到Picasso有緩存機(jī)制,這個(gè)方法還是有一點(diǎn)價(jià)值的,提前加載放到緩存,后面加載速度會(huì)更快。
/*** Asynchronously fulfills the request without a {@link ImageView} or {@link Target},* and invokes the target {@link Callback} with the result. This is useful when you want to warm* up the cache with an image.* <p>* <em>Note:</em> The {@link Callback} param is a strong reference and will prevent your* {@link android.app.Activity} or {@link android.app.Fragment} from being garbage collected* until the request is completed.*/public void fetch(Callback callback) {long started = System.nanoTime();if (deferred) {throw new IllegalStateException("Fit cannot be used with fetch.");}if (data.hasImage()) {// Fetch requests have lower priority by default.if (!data.hasPriority()) {data.priority(Priority.LOW);}Request request = createRequest(started);String key = createKey(request, new StringBuilder());Bitmap bitmap = picasso.quickMemoryCacheCheck(key);if (bitmap != null) {if (picasso.loggingEnabled) {log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY);}if (callback != null) {callback.onSuccess();}} else {Action action =new FetchAction(picasso, request, memoryPolicy, networkPolicy, tag, key, callback);picasso.submit(action);}}}6. 自定義Picasso
默認(rèn)使用Picasso.with(context)可以快速的構(gòu)建Picasso實(shí)例,但是Picasso支持?jǐn)U展自定義Picasso,也就是一些默認(rèn)的配置,我們可以自己來(lái)調(diào)控。
可以看到Picasso.Builder方法存在很多可配置的內(nèi)容,downloader, executor, memoryCache,listener等等都是可以自己設(shè)置的,配置完成后調(diào)用
builder()方法即可返回Picasso實(shí)例。
還可以通過(guò)如下方法設(shè)置全局Picasso實(shí)例。
7. 類圖
請(qǐng)適當(dāng)放大后查看。
8. 主要流程圖
請(qǐng)適當(dāng)放大后查看。
總結(jié)
以上是生活随笔為你收集整理的《Android开源库》Picasso的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 妇女节 | 卓然而立,绽放光芒!
- 下一篇: Android 实现倒计时动画效果