【问题标题】:How to efficiently manage image resources, both local and networked, in Android?如何在 Android 中有效地管理本地和网络的图像资源?
【发布时间】:2014-12-14 03:10:07
【问题描述】:

我正在开发一个应用程序,这需要 -

  1. 从本地通讯录中提取联系方式和图片。
  2. 每隔一段时间将此联系人数据(全部)同步到服务器。
  3. 在需要时从服务器中提取联系人数据(以及图像)。

我基本上知道如何单独实现它们。例如,我已经设法拉取本地联系人,但我还没有达到 2 和 3。我对他们没有几个问题。

  1. 我在哪里保存图像(本地和网络)?我需要将它们保存在任何特定文件夹中吗?如果是,那么推荐的方法是什么?
  2. 我在另一个项目中使用过 volley 库,我希望在这里再次使用它。 AFAIK,凌空在内存中缓存网络图像。但我相信在我的应用中,可能会有用户拥有超过 2000 条联系数据。我的直觉是,并非所有图像都会永远保留在缓存中,所以如果我希望我的应用程序离线工作,我需要将图像存储在本地。我对在哪里存储图像以及如何实现这一点感到困惑。请注意,此应用会被频繁访问。
  3. 通过网络将图像数据发送到服务器的推荐方式是什么。

这些问题可能看起来很宽泛,但考虑到单个应用程序,我觉得它们是紧密耦合的。我期待专家对实现这些功能的推荐方法发表意见。

谢谢!

【问题讨论】:

  • 作为旁注,出于个人经验考虑您是否真的需要缓存所有图像。一方面,您总是可以在运行时延迟加载图像(因此将图像缓存在 RAM 中,而无需将图像缓存在系统上的文件中)。另一方面,如果你想在手机本身缓存图片,尽量压缩大小,同时不丢失明显的细节[这当然也取决于屏幕大小]
  • 现在我重新阅读了问题+评论,以上内容仅适用于您几乎只在线的情况。那么,旁注是旁注吗?您可以同时做一些 - 通常,如果可能的话,延迟加载并缓存/保存一定数量的联系人的图像[最有可能用户会看到 85% 的时间,或者那些可能会在离线时看到的图像]
  • 我正在使用延迟加载来加载其他数据。现在我已经学会了拉图像,希望能尽快整合它。我对有效实现图像的方法感到困惑,因为我相信大约 2000 次图像接触是一件很难处理的事情。

标签: android image android-volley


【解决方案1】:

您通常将它们保存到内部文件夹或目录中的 SD 卡中。内部数据文件夹将被锁定到您的应用程序(除非手机已root)并且其他应用程序无法访问,SD卡将仅在4.3及更高版本上。无论哪种方式,您都应该管理缓存的数据量,设置一个限制并且不允许它超过这个值(在某些情况下将它们踢出,很可能是 LRU 或 LFU)。您需要手动完成或找到一个库来为您完成,它不是 Android 内置的。

至于从服务器下载它们 - 通常它只是一个 HTTP 请求,带有一个 Web 服务,该服务将在发送图像结果或错误之前进行任何必要的隐私检查。你不想在这里做 JSON 之类的东西,它只会浪费带宽。

【讨论】:

  • 我实际上正在考虑 LRU 缓存。我正在通过延迟加载加载其他数据,我还没有集成图像。我也对卸载 SD 卡可能存在的危险感到困惑。
  • 在这种情况下,您将无法读取文件。但如果处理得当,它看起来与缓存未命中相同,在这种情况下,您需要从网络下载新副本。
【解决方案2】:
  1. 没有“推荐的图像目录”。决定权在你。但是您必须始终记住,用户设备上的内存是有限的,在某些手机上,甚至额外的几兆字节都是不合适的支出。 The docs 很清楚。
  2. 在用户设备上保存约 2000 张照片不是一个好主意。但这又取决于你。 Volley 库用于一般的 https 交互,但不适用于图像下载、编码和缓存。 Picasso 旨在处理图像:从网络或Uri 加载图像,具有缓存大小设置和许多其他功能。
  3. 这取决于您的服务器。如果您需要发送一些额外的数据,最常见的方式就是 POST http 请求或多部分请求。

【讨论】:

  • 感谢您的建议。我知道毕加索。好吧,如果我想向服务器发送数据(联系方式中的数据,包括图像),我不应该使用 Volley 吗?或者我应该只包含 Picasso 来处理图像并使用 Volley 来处理其他数据?
【解决方案3】:

关于第三个问题,如果你打算继续使用Volley,你可以尝试覆盖getBody()来返回图片的字节数,其余的参数应该在URL,这种方式会同时使用 GET 和 POST 方法。

public class ContactRequest extends StringRequest {

    public static String buildRequestUrl(String url,
        Map<String, String> params, String paramsEncoding) {
        StringBuilder urlBud = new StringBuilder(url).append('?');
        try {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                urlBud.append(URLEncoder.encode(entry.getKey(), paramsEncoding));
                urlBud.append('=');
                urlBud.append(URLEncoder.encode(entry.getValue(), paramsEncoding));
                urlBud.append('&');
            }
            return urlBud.toString();
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("Encoding not supported: " + paramsEncoding);
        }
    }

    private String imageFilePath;

    public ContactRequest(String url, String imageFilePath,
        Response.Listener<String> listener, Response.ErrorListener errorListener) {
        super(Method.POST, url, listener, errorListener);
        this.imageFilePath = imageFilePath;
    }

    @Override
    public byte[] getBody() throws AuthFailureError {
        return getBytesFromFile(new File(imageFilePath));
    }
}

构建ContactRequest 并像这样向 RequestQueue 提供服务:

String originUrl = "http://.../contact_push.do";
String imageFilePath = "/sdcard/.../contact_avatar_path";
Map<String, String> params = new HashMap<String, String>();
params.put("firstName", "Vince");
params.put("lastName", "Styling");
new ContactRequest(
    ContactRequest.buildRequestUrl(originUrl, params, HTTP.UTF_8),
    imageFilePath, null, null);

因为我以前从未遇到过这个问题,所以我不确定这个请求是否可以正确到达服务器,这对我来说是一个未经测试的解决方案,希望可以帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-31
    • 1970-01-01
    • 1970-01-01
    • 2010-10-30
    • 1970-01-01
    相关资源
    最近更新 更多