如何让Picasso / Glide与Html.ImageGetter一起使用来缓存图像?

时间:2015-10-09 13:50:05

标签: android caching picasso android-bitmap android-glide

感谢@Budius所做的一切努力。

我的应用程序的大部分图像工作都可以由Picasso / Glide处理,但是,一些图像显示在TextView Html.fromHtml之内。 TextView中的图像也经常使用。

但是,我不知道如何使用Picasso / Glide为传递给getDrawable()的{​​{1}}实施ImageGetter方法。是否可以在Html.fromHtml和其他位图中为这些图片共享Picasso / Glide的相同缓存?

或者我应该使用自定义TextView来分别从LruCache缓存这些图片吗?这样会增加OOM错误的风险吗?我认为使用2个不同的系统处理图像会产生不必要的工作量。

更新:我尝试使用Picasso的ImageGetter,但是文档说

.get()

因此在这种情况下不使用缓存。

更新 @Budius的答案是正确的,但是/** * The result of this operation is not cached in memory because the underlying * {@link Cache} implementation is not guaranteed to be thread-safe. */ 的设置边界的代码丢失,这使得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); } } 中的图像会有一些奇怪的行为。有时图像无法刷新,除非您切换到另一个应用程序并切换回来,并且图像的位置严重不正确。

更新:我已经发布了以下所有测试代码。还有一些错误。如果没有占位符,它仍会抛出NPE。使用占位符,行为非常奇怪。我第一次输入TextView时,会显示占位符,但不会更改为下载的图片。但是在我切换到另一个应用程序或按下后退按钮并再次输入TestActivity后,会显示图片(可能是因为它在缓存中?)。

而且pic的大小也是正确的,但这个地方仍然没有留给图像。如果我拨打TestActivity而不是mDrawable.setBounds(getBounds());,则不会显示。

DrawableWrapper

mDrawable.setBounds(0,0,getIntrinsicWidth(),getIntrinsicHeight());

PicassoTargetDrawable

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);
        }
    }
}

测试活动

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();
    }
}

1 个答案:

答案 0 :(得分:0)

我的建议是返回一个wrap drawable。并继续使用Picasso下载图像。

在以下链接中,您可以找到一个DrawableWrapper,它来自Googles支持库,但它不是公共文档的一部分,所以我只是将整个代码复制到您的项目中{{3 }}

然后你从中创建一个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应该使用的Bounds。如果您告诉新的mDrawable它可以使用它想要的任何大小,它将使用它想要的任何大小。因此,不应传递其自身的固有宽度/高度,而应传递给予WrapDrawable的大小

public void setWrappedDrawable(Drawable drawable) {
    if (mDrawable != null) {
       mDrawable.setCallback(null);
    }
    mDrawable = drawable;
    if (drawable != null) {     
        mDrawable.setBounds(getBounds());
        drawable.setCallback(this);
    }
}