Picasso中一些問題的解決方法

比較大的圖片無法加載

如果你的項(xiàng)目中有以下的代碼,并且使用 2.5.2 (以前有沒有這個(gè)問題我沒有去驗(yàn)證),很可能會(huì)出現(xiàn)較大的圖片無法加載

Picasso.with(context).load(uri)
        .resize(width, height)
        .into(target);

目前的解決辦法是將gradle文件中的這一句

compile 'com.squareup.picasso:picasso:2.5.2'

替換為

compile 'com.squareup.picasso:picasso:2.6.0-SNAPSHOT'

也就是說在 2.5.2 以后的代碼會(huì)修復(fù)這個(gè)BUG(然而Picasso已經(jīng)N年不更新了,據(jù)說打算release 3.0.0)
那么這個(gè)問題為何會(huì)出現(xiàn)呢? 這里需要通過下面的代碼拿到 Picasso 加載圖片失敗的日志

mPicasso = new Picasso.Builder(context.getApplicationContext())
        .listener(new Picasso.Listener() {
            @Override
            public void onImageLoadFailed(Picasso picasso, Uri uri, Exception exception) {
                Log.e(TAG, uri.toString(), exception);
            }
        }).build();

當(dāng)圖片加載無法加載的時(shí)候會(huì)有這樣一條log

Picasso加載大圖失敗log.png

這個(gè)異常是由 MarkableInputStream.java 拋出,對(duì)應(yīng)的代碼如下

public void reset(long token) throws IOException {
  if (offset > limit || token < reset) {
    throw new IOException("Cannot reset");
  }
  in.reset();
  skip(reset, token);
  offset = token;
}

其中l(wèi)imit的大小是65536,而offset是表示讀取流的位置,在 BitmapHunter.java 中調(diào)用了 MarkableInputStream.java 中的 reset() 方法,具體代碼如下:

static Bitmap decodeStream(InputStream stream, Request request) throws IOException {
  ...
  final boolean calculateSize = RequestHandler.requiresInSampleSize(options);
  ...
  if (calculateSize) {
    BitmapFactory.decodeStream(stream, null, options);
    RequestHandler.calculateInSampleSize(request.targetWidth, request.targetHeight, options,
        request);
    markStream.reset(mark);
  }
  Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
  ...
}

這里是圖片加載比較常見的操作,先計(jì)算bitmap的options,然后才會(huì)真正的將圖片加載到內(nèi)存中。在獲取正確的options之后,Picasso會(huì)將整個(gè)流reset,這個(gè)時(shí)候如果offset大于limit就會(huì)拋出異常,導(dǎo)致圖片加載失敗。
Picasso在 2.5.2 以后使用了動(dòng)態(tài)調(diào)整limit的方式,增長(zhǎng)limit大小,從而解決了這個(gè)問題
Reference:
Added dynamic limit option to MarkableInputStream
java.io.IOException: Cannot reset (Huge photo loading)

首次加載的時(shí)候圖片無法顯示

如果你的代碼是下面這種寫法,那么恭喜你,這個(gè)問題也是可以解決的

Picasso.with(context).load(image.getUri())
        .into(new Target() {
            @Override
            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                // your code
            }

            @Override
            public void onBitmapFailed(Drawable errorDrawable) {
                // your code
            }

            @Override
            public void onPrepareLoad(Drawable placeHolderDrawable) {
                // your code
            }
        });

解決方法是把 Target 通過強(qiáng)引用(比如類的屬性或者M(jìn)ap之類)保存起來,例如

class Test {
    private Picasso mPicasso;
    private final Map<String, Target> mTargetMap;

    Test(Context context) {
        mPicasso = new Picasso.Builder(context.getApplicationContext())
                .listener(new Picasso.Listener() {
                    @Override
                    public void onImageLoadFailed(Picasso picasso, Uri uri, Exception exception) {
                        Log.e(TAG, uri.toString(), exception);
                    }
                }).build();
        mPicasso.setLoggingEnabled(true);
        mTargetMap = new HashMap<>();
    }

    public void loadBitmap() {

        Target target = new Target() {
            @Override
            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
            }

            @Override
            public void onBitmapFailed(Drawable errorDrawable) {
            }

            @Override
            public void onPrepareLoad(Drawable placeHolderDrawable) {
            }
        };
        mTargetMap.put(key, target);

        mPicasso.load(uri)
                .into(mTargetMap.get(key));
    }

}

這個(gè)問題產(chǎn)生的原因是target在Picasso內(nèi)部是通過弱引用保存的,就會(huì)導(dǎo)致target很容易被GC清理,這時(shí)候 onBitmapLoaded 就不會(huì)被回調(diào)了
Reference:
Target.onBitmapLoaded() method not called sometimes

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 這么久以來雖然經(jīng)常用到一些圖庫(kù),但是自己從來沒有真正整理過我們使用過的這些東西有什么不同點(diǎn),我們?yōu)槭裁匆x擇這個(gè)圖...
    黑石ZB閱讀 3,883評(píng)論 1 16
  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom閱讀 3,224評(píng)論 0 3
  • 簡(jiǎn)單說說我最常用的圖片加載庫(kù)Picasso 對(duì)于一個(gè)需要展示很多圖片或較多圖片的App來說,一個(gè)好的圖片加載框架是...
    _飛翔的荷蘭豆閱讀 3,706評(píng)論 5 36
  • 1. 簡(jiǎn)介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存儲(chǔ)過程以及高級(jí)映射的優(yōu)秀的...
    笨鳥慢飛閱讀 6,280評(píng)論 0 4
  • 3月1日,陽(yáng)光溫暖的灑在身上,楊楊很開心,臉上帶著不自主就泛滿的笑意,一頭烏黑長(zhǎng)發(fā)被微風(fēng)輕吹的有些散亂,她腳步也很...
    長(zhǎng)聞閱讀 306評(píng)論 0 0

友情鏈接更多精彩內(nèi)容