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

2024-02-15

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

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

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

或者我应该使用自定义的LruCache而是以缓存这些图片的形式ImageGetter分别地?这种方式会增加 OOM 错误的风险吗?我认为使用两个不同的系统来处理图像会产生不必要的工作量。

Update:我尝试使用.get()毕加索的作品,但医生说

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

所以本例中没有使用缓存。

Update:@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);
    }
}

Update:,问题仍然没有解决。如果您实施上述解决方案,则图像会出现一些奇怪的行为TextView。有时,除非切换到另一个应用程序再切换回来,否则图像无法刷新,并且图像位置严重不正确。

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

而且图片的大小是正确的,但仍然没有留下图像的位置。如果我打电话mDrawable.setBounds(getBounds());代替mDrawable.setBounds(0,0,getIntrinsicWidth(),getIntrinsicHeight());,则不会显示。

可绘制包装器

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

测试活动

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

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

在下面的链接中,您可以找到一个 DrawableWrapper,它来自 Google 的支持库,但它不是公共文档的一部分,所以我只需将整个代码复制到您的项目中https://android.googlesource.com/platform/frameworks/support/+/master/v7/appcompat/src/android/support/v7/graphics/drawable/DrawableWrapper.java https://android.googlesource.com/platform/frameworks/support/+/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.:我写的这一切都没有查太多资料,可能会有一些错别字和一些需要整理的问题,但这当然足以让你理解这个概念。

update:只是更正您的代码。

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);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使 Picasso/Glide 与 Html.ImageGetter 一起缓存图像? 的相关文章

随机推荐

  • Spring MVC ExceptionHandler 实现平静和正常

    我想处理正常请求和休息 ajax 请求的异常 这是我的代码 ControllerAdvice public class MyExceptionHandler ExceptionHandler Exception class public M
  • wampserver 主页仅从本地主机可见

    最近我用过WAMPserver 在Windows机器上搭建服务器环境 一切都很好 但我有一个小问题 每个人都可以访问wampserver主页 因此他们可以看到同一服务器上托管的其他网页 服务器文件系统等 网页的 URL 具有以下格式 hos
  • Android PlaceFilter 与 Google Places API 的使用

    我正在尝试使用 Google Places API 并且想将搜索过滤为仅健身房类型 我正在使用给出的代码https developers google com places https developers google com place
  • Mongoose 查询最近 24 小时内的文档,每小时仅查询一个文档

    我正在编写一个应用程序 其中有一些天气传感器每 5 分钟将空气温度和湿度发送到服务器 我想画一张图表来显示温度和湿度如何变化 即一夜之间 我的想法是根据过去 24 小时的数据绘制图表 我自己无法弄清楚 所以我想也许我可以在这里寻求帮助 当然
  • 如何使用操作和控制器名称获取 ActionDescriptor

    给定操作名称 控制器名称和 HTTP 动词 GET POST 等 是否可以检查该操作是否具有 即被修饰 特定的操作过滤器属性 请注意 操作和控制器不是当前操作和控制器 而是可以是应用程序中的任何操作和控制器 Thanks 我已经回答了我自己
  • mac下appium的安装目录

    我已经从 MAC 终端安装了 appium 1 5 1 安装没问题 但由于某种原因我需要安装它的路径 谁能告诉我安装目录在哪里 如果您安装了 GUI appium 应用程序 您可以在 Mac 的 Launchpad 中单击其图标的应用程序
  • 服务结构提醒

    文档 https learn microsoft com en us azure service fabric service fabric reliable actors timers reminders actor reminders
  • ASP.NET Core RC2 区域未发布

    所以我刚刚更新了我的应用程序以使用 ASP NET Core RC2 我使用 Visual Studio 发布了它 并注意到我的区域未发布 这张快照来自src MyProject bin Release PublishOutput 这是我的
  • python pdb:捕获异常后恢复代码执行?

    如果我运行代码ipython pdbmagic 启用并且代码抛出异常 有什么办法告诉代码之后继续执行吗 例如 假设例外是ValueError x 0 not allowed 我可以在 pdb 中设置x 1并允许代码继续 恢复 执行 我认为您
  • Fancybox (jQuery) - 将信息从父级传递到 iframe 并将 iframe 传递回父级

    我正在尝试在我的页面上打开一个 fancybox iframe 将一些基本信息传递给 iframe 然后我想让 iframe 与其父级对话 我静态地传递 nameid 1 尽管我真的很想将其作为变量 例如 var nameid this a
  • 使用 Entity Framework 6 迁移创建索引

    有没有办法使用实体框架代码优先迁移在 MS SQL Server 数据库中创建索引 如果索引必须是 至少下降一列 包括其他列 它必须产生这样的东西 CREATE NONCLUSTERED INDEX IX IndexName ON dbo
  • NSTableView 中的 NSButtonCell:点击处理

    I set NSButtonCell作为一种细胞类型Table Column in my NSTableView 我实施了一个IBAction方法 但我无法将其连接NSButtonCell在 IB 中 线路不想突出显示来自的按钮NSTabl
  • PostgreSql:仅选择周末

    我有一张包含公共假期的表格 id description date 1 Ferragosto and Assunzione 2012 08 15 00 00 00 2 Tutti i santi Ognissanti 2012 11 01
  • 在 Maven 依赖项中插入许可证

    我已经使用 JxBrowser 进行了一些测试 并打算将其添加到我的学术项目中 然而 它是一个 Maven 项目 我使用 Netbeans IDE 开发 虽然我添加了 TeamDev JxBrowser 存储库 但 JxBrowser 依赖
  • 美丽的汤不等待页面完全加载

    因此 使用下面的代码 我想打开一个公寓网站 URL 并抓取网页 唯一的问题是 Beautiful Soup 不会等到整个网页渲染完毕 公寓在加载到页面上之前不会在 html 中呈现 这需要几秒钟的时间 我该如何解决 from urllib
  • 如何让 F# 与 Mono 一起工作?

    我似乎找不到单声道的编译器 插件 有吗 Go here http www microsoft com download en details aspx id 11100并下载 fsharp zip 解压并打开创建的文件夹 打开终端并以 ro
  • 如何搜索包含子字符串的行?

    如果每次用户提交表单时我都在 ODBC 数据库中存储 HTML TEXTAREA 那么什么是SELECT检索语句 1 包含给定子字符串的所有行 2 不包含给定子字符串的所有行 搜索是否区分大小写 编辑 如果LIKE SUBSTRING 会很
  • 为什么Python不是完全面向对象的? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我想知道为什么Python不是完全面向对象的 例如 它不支持 private public protected 访问级别修饰符 这样做的优点和缺
  • 如何使输入按钮在所有浏览器中看起来完全相同?

    我正在设计我的表单按钮 如下所示 CSS RESET margin 0 padding 0 form input button padding 2px
  • 如何使 Picasso/Glide 与 Html.ImageGetter 一起缓存图像?

    感谢 Budius 所做的一切努力 我的应用程序的大部分图像工作可以由 Picasso Glide 处理 但是 某些图像显示在TextView by Html fromHtml 以及图像中TextView也经常使用 但是 我不知道如何实施g