3

感谢@Budius 所做的所有努力。

我的应用程序的大部分图像工作可以由 Picasso/Glide 处理,但是,一些图像显示在TextViewby Html.fromHtml. 而且里面的图片TextView也经常使用。

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

或者我应该使用自定义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。有时候图片无法刷新,除非你切换到另一个应用程序再切换回来,并且图片的位置严重不正确。

更新:我在下面发布了所有测试代码。还是有一些bug。如果没有占位符,它仍然会抛出 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

我的建议是返回一个可绘制的包装。并继续使用毕加索下载图像。

在以下链接中,您可以找到一个 DrawableWrapper,它来自 Google 的支持库,但它不是公共文档的一部分,所以我只需将整个代码复制到您的项目中https://android.googlesource.com/platform/frameworks/支持/+/master/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 回答