3

@Budius の尽力に感謝します。

私のアプリの画像処理の大部分は Picasso/Glide で処理できますが、一部の画像は by で表示さTextViewHtml.fromHtmlます。また、 の画像TextViewも頻繁に使用されます。

ただし、渡された togetDrawable()に対して Picasso/Glide でメソッドを実装する方法がわかりません。これらの画像と他のビットマップの Picasso/Glide の同じキャッシュを共有することは可能ですか?ImageGetterHtml.fromHtmlTextView

または、代わりにカスタムを使用して、これらの画像フォームを個別LruCacheにキャッシュする必要がありますか? ImageGetterこの方法は、OOM エラーのリスクを高めますか? また、画像を処理するために 2 つの異なるシステムを使用することは、不要な作業負荷を生み出すと思います。

更新:ピカソを使用しようとしまし.get()たが、ドキュメントには次のように書かれています

/**
 * The result of this operation is not cached in memory because the underlying    
 * {@link Cache} implementation is not guaranteed to be thread-safe.
 */

したがって、この場合、キャッシュは使用されません。

更新: @Budius の答えは正しいですが、 の境界を設定するコードDrawableが欠落しているため、Drawableに表示されませんTextView。そこで、DrawableWrapperクラスのコードを次のように変更しました。

public void setWrappedDrawable(Drawable drawable) {
    if (mDrawable != null) {
        mDrawable.setCallback(null);
    }
    mDrawable = drawable;
    if (drawable != null) {
        mDrawable.setBounds(0,0,mDrawable.getIntrinsicWidth(),mDrawable.getIntrinsicHeight());
        drawable.setCallback(this);
    }
}

更新:、問題はまだ解決されていません。前述のソリューションを実装すると、 の画像に奇妙な動作が発生しTextViewます。別のアプリに切り替えて元に戻さない限り、画像を更新できず、画像の位置が大幅に間違っている場合があります。

更新:以下のテスト用のすべてのコードを投稿しました。まだいくつかのバグがあります。プレースホルダーがなくても、NPE がスローされます。プレースホルダーを使用すると、動作が非常に奇妙になります。初めて入力するTestActivityと、プレースホルダーが表示されますが、ダウンロードした写真に変わりません。しかし、別のアプリに切り替えるか、戻るボタンを押してTestActivityもう一度入力すると、写真が表示されます(キャッシュにあるためですか?)。

また、写真のサイズは正しいですが、画像の場所はまだ残っていません。mDrawable.setBounds(getBounds());の代わりに呼び出すとmDrawable.setBounds(0,0,getIntrinsicWidth(),getIntrinsicHeight());、表示されません。

DrawableWrapper

public class DrawableWrapper extends Drawable implements Drawable.Callback {
    private Drawable mDrawable;

    public DrawableWrapper(Drawable drawable) {
        setWrappedDrawable(drawable);
    }

    @Override
    public void draw(Canvas canvas) {
        mDrawable.draw(canvas);
    }
    @Override
    public int getIntrinsicWidth() {
        return 384;
    }

    @Override
    public int getIntrinsicHeight() {
        return 216;
    }
    //... other delegation methods are omitted

    public void setWrappedDrawable(Drawable drawable) {
        if (mDrawable != null) {
            mDrawable.setCallback(null);
        }
        mDrawable = drawable;
        if (drawable != null) {
            mDrawable.setBounds(0,0,getIntrinsicWidth(),getIntrinsicHeight());
            drawable.setCallback(this);
        }
    }
}

PicassoTargetDrawable

public class PicassoTargetDrawable extends DrawableWrapper
        implements Target {

    private Context context;

    public PicassoTargetDrawable(Context context) {
        super(new ColorDrawable(0));
        // use application context to not leak activity
        this.context = context.getApplicationContext();
    }

    public void onBitmapFailed(Drawable errorDrawable) {
        setWrappedDrawable(errorDrawable);
        invalidateSelf();
    }

    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
        setWrappedDrawable(new BitmapDrawable(context.getResources(), bitmap));
        context = null;
        invalidateSelf();
    }

    public void onPrepareLoad(Drawable placeHolderDrawable) {
        setWrappedDrawable(placeHolderDrawable);
        invalidateSelf();
    }
}

テスト活動

public class TestActivity extends FragmentActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView textView = new TextView(this);
        textView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
        setContentView(textView);
        String html = "<div>test<br/>" +
                "<img src=\"http://i2.cdn.turner.com/money/dam/assets/150910165544-elon-evo-open-still-384x216.png\"></img>" +
                "<br/>/test</div>";
        textView.setText(Html.fromHtml(html, new Html.ImageGetter() {
            @Override
            public Drawable getDrawable(String source) {
                PicassoTargetDrawable d = new PicassoTargetDrawable(TestActivity.this);
                Picasso.with(TestActivity.this)
                        .load(source)
                        //add placeholder here
                        .into(d);
                return d;
            }
        }, null));
    }
}
4

1 に答える 1

0

私の提案は、ラップ ドローアブルを返すことです。引き続き Picasso を使用して画像をダウンロードします。

次のリンクで DrawableWrapper を見つけることができます。これは Google のサポート ライブラリからのものですが、公開ドキュメントの一部ではないため、コード全体をプロジェクトhttps://android.googlesource.com/platform/frameworks/にコピーするだけです。サポート/+/マスター/v7/appcompat/src/android/support/v7/graphics/drawable/DrawableWrapper.java

そして、そこから を作成しますPicassoTargetDrawable

public class PicassoTargetDrawable extends DrawableWrapper
        implements Picasso.Target {

    private Context context;

    public PicassoTargetDrawable(Context context) {
        super(new ColorDrawable(0));
        // use application context to not leak activity
        this.context = context.getApplicationContext();
    }

    public void onBitmapFailed(Drawable errorDrawable) {
        setWrappedDrawable(errorDrawable);
        invalidateSelf();
    }

    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
        setWrappedDrawable(new BitmapDrawable(context.getResources(), bitmap));
        context = null;
        invalidateSelf();
    }

    public void onPrepareLoad(Drawable placeHolderDrawable) {
        setWrappedDrawable(placeHolderDrawable);
        invalidateSelf();
    }
}

あとは積み込むだけです

public void Drawable getDrawable(String source) {
    PicassoTargetDrawable d = new PicassoTargetDrawable(context);
    Picasso.with(context)
       .load(source)
       ..... add here onError and placeholder drawables
       .into(d);
    return d;
}

PS .: あまり調べずに書いたので、おそらくいくつかのタイプミスや整理すべき問題があるでしょうが、概念を理解するには十分です。

更新: コードを修正するだけです。

TextView は、WrapDrawable に使用する境界を既に伝えています。新しい mDrawable に、必要なサイズを使用できることを伝えている場合は、必要なサイズを使用します。したがって、独自の固有の幅/高さを渡す代わりに、WrapDrawable に与えられたサイズを渡す必要があります。

public void setWrappedDrawable(Drawable drawable) {
    if (mDrawable != null) {
       mDrawable.setCallback(null);
    }
    mDrawable = drawable;
    if (drawable != null) {     
        mDrawable.setBounds(getBounds());
        drawable.setCallback(this);
    }
}
于 2015-10-09T14:09:07.373 に答える