我不清楚 Android 在缓存方面是如何处理图像的。
比方说,我有一个应用程序 这是 3 层深(因此,它有 3 个 Activity 被推到 彼此)。
如果我的 3 个 Activity 中的每一个都在所有 3 个 Activity 的工具栏中显示 3 个图像,我的理解是相同的 3 个图像将被加载到内存中 3 次。这导致 9 张图像占用内存,尽管实际上只有 3 张图像,但它们只是 多次加载。
此外,假设我的主要 Activity 有一个 ListView,显示有关通过网络检索的文档的信息。
每个 ListView 项都定制为显示 3 条信息:
- 代表一种文档类型的图像(即 .txt、.pdf、.docx、.js 等)
- 代表标题的字符串
- 代表一些描述的字符串
如果上面的 ListView 加载了数百万个项目(每个项目代表一个文档)并假设所有项目都是一个 word 文档,那么 .docx 类型的所有数百万个图像都会被下载,但它实际上只是我需要的一个图像。这似乎是对网络带宽和内存的明显浪费,我宁愿只下载一张图像并使用它一百万次,也不愿下载一百万张图像并每张仅使用一次。
所以,在这样的情况下,我不知道我需要什么样的图像,因此图像 Assets 中没有它,而是依赖下载的图像来显示文档类型,是否有某种缓存策略我可以用于避免必须下载相同的图像百万次?
Android已经提供了吗?
更新
在我上面的工具栏图像示例中,这些是 Android 资源图像(因此,可绘制对象)。那么,对于这些,我相信它们是默认缓存的?
但是,ListView 图像是从网络下载的图像,因此在我上面的示例中,自定义 ListViewItem 由 3 个 View (一个图像和 2 个标签)组成,图像将在渲染 ListView 的同时下载.我提供了一个只有 3 个 View 的简单 ListView 项目,但它可能是 10 个 View (比如 4 个图像和 6 个标签)。重点是在ListView的渲染过程中,一张图片是从网上下载的。由于该图像可能会重复,如何避免下载相同的图像而使用缓存的图像?
最佳答案
首先是项目列表
ListView
不会以您假设的这种低效方式工作。但是如果你真的关心效率和处理非常大的数据列表,建议使用 RecyclerView
。 here 两者的比较有很好的讨论和答案.
如果您计划处理包含某些有限的文档类型图标集合的数千个文档的列表,最好的做法是使用位图的 HashMap,您将链接到特定的列表项(无论您选择什么使用:RecyclerView
或 ListView
)。
这里是一个简单的例子(它不是正确的java,只是为了给出一个想法)ListViews的适配器类:
public class DocumentsListAdapter extends ArrayAdapter<String> {
private final HashMap<String, Bitmap> docIcons = HashMap<String, Bitmap>()
private final Activity mContext;
private final List<String> mItems;
public DocumentsListAdapter(Activity context, List<String> items) {
docIcons.put("docx", loadDocBitmapFromDisk());
docIcons.put("xls", loadXlsBitmapFromDisk());
docIcons.put("pdf", loadPdfBitmapFromDisk());
// and so on...
mItems = items;
mContext = context;
}
@Override
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View rowView= inflater.inflate(R.layout.list_single, null, true);
TextView txtTitle = (TextView) rowView.findViewById(R.id.txt);
ImageView imageView = (ImageView) rowView.findViewById(R.id.img);
txtTitle.setText(mItems.get(position));
if(items.get(position).endsWith(".docx")) {
imageView.setImageBitmap(docIcons.get("docx"))
} // and so on for other types...
}
}
这个例子不包括你如何获得你的图标。您可以从互联网上下载它们,将它们存储在磁盘上,当应用程序需要这些图标时——您可以将它们作为位图从磁盘加载并在内存中仅存储一次每个位图并在 View 中重用它们。将此逻辑与 RecyclerView 一起实现,您将获得相当高效的应用程序,它不会浪费内存并且响应速度非常快。
您不必在适配器中存储带位图的 HashMap
,但如果您只在一个地方使用它,这是一个不错的选择。如果您需要在不同的 Activity 中使用它,请考虑将此 HashMap
保存在其他地方,这样每次用户在使用类似 ListViews
的不同 Activity 之间切换时都不会重新加载它.
处理具有相同图像的多个 Activity
关于 Activity ,这取决于您如何存储图像。如果它们也从 Internet 下载并缓存在磁盘上,您可以按照此答案的 ListView 部分中的描述进行操作。只需将您加载到内存中的图像列表保存在某处并使用
imageView.setImageBitmap(someBitmap)
当您需要在 Activity 的特定部分显示它时。
如果您使用的是应用程序资源,那就更容易了,因为您可以这样做:
Drawable dr = context.resources.getDrawable(R.drawable.my_favourite_image);
imageView.setImageDrawable(dr);
所有与内存高效使用有关的工作都是在幕后完成的。
如何避免下载相同的图像而使用缓存的图像
这取决于您将如何跟踪每张图片的独特性。例如。如果每个图像都有唯一的 URL,最基本的解决方案是使用以图像 URL 为键的 HashMap。
更复杂但更灵活和正确的决定是使用类似 Guava 的东西缓存工具。这不是特定于 Android 的,而且在这个答案中涵盖的主题非常广泛,但您可以 take a look here .
尽管如此,如果您打算弄乱图像的复杂布局并关心性能,请检查 Anko
和 this benchmark .这与内容缓存无关,但布局渲染性能可以提高 3 倍以上。
关于Android - 处理作为解决方案一部分的图像和下载的图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45666661/