Android - 处理作为解决方案的一部分的图像和下载的图像

时间:2017-08-14 02:23:53

标签: android image-caching

我不清楚在缓存方面如何在Android中处理图像。

让我们说,我有一个应用程序 这是3级深度(因此,它有3个活动被推到顶部 彼此)。

如果我的3个活动中的每个活动在所有3个活动的工具栏中显示3个图像,我的理解是相同的3个图像将在内存中加载3次。这导致9张图像记忆,虽然它实际上只有3张图像,它们只是 多次加载。

另外,假设我的主要活动有一个ListView,显示有关通过网络检索的文档的信息。

每个列表视图项目都是自定义的,以显示3条信息:

  • 表示某种文件的图像(即.txt,.pdf,.docx,.js,...)
  • 表示标题的字符串
  • 表示某些描述的字符串

如果上面的ListView加载了百万个项目(每个项目代表一个文档)并假设所有项目都是word文档,则下载了.docx类型的所有百万个图像,但它实际上只是我需要的一个图像。这似乎是对网络带宽和内存的明显浪费,我只想下载一个图像并使用它一百万次,而不是下载百万个图像,并且每次只使用一次。

所以,在这样的场景中,我不知道我需要什么样的图像,因此在图像资产中没有它,而是依靠下载的图像来显示文档类型,是否有某种缓存策略我可以使用以避免必须下载相同的图像数百万次?

它是否已由Android提供?

更新

在我上面的工具栏图像示例中,这些是Android资源图像(因此,drawables)。那么,对于这些,我相信这些是默认缓存的吗?

但是,ListView图像是从Web下载的图像,因此在上面的示例中,自定义ListViewItem由3个视图(一个图像和2个标签)组成,Image将在同一时间下载ListView 。我提供了一个只有3个视图的简单ListView项目,但它可能是10个视图(比如4个图像和6个标签)。重点是在ListView的渲染过程中从Web下载一个图像。由于该图像可能会重复,如何下载同一图像但使用缓存图像?

1 个答案:

答案 0 :(得分:1)

首先关于项目列表

ListView无法以您假设的低效方式运作。但如果你真的关心效率和处理真正庞大的数据列表,建议使用RecyclerView。对here的比较进行了很好的讨论和回答。

如果您计划使用某些有限的文档类型图标集处理数千个文档的列表,最佳做法是使用位图的HashMap,您将链接到特定列表项(无论您将选择什么使用:RecyclerViewListView)。

这是一个简短的例子(这不是正确的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...
    }
}

此示例未涵盖您获取图标的方式。您可以从Internet下载它们,将它们存储在磁盘上,当应用程序需要这些图标时 - 您将它们作为位图从磁盘加载并在每个位图中仅存储一次内存并在视图中重复使用它们。将这个逻辑与RecyclerView一起实施,您将获得相当高效的应用程序,它不会浪费内存并且响应速度非常快。

您不必在适配器中存储带有位图的HashMap,但如果您只在一个地方使用它,那么它是不错的选择。如果您需要在不同的活动中使用它,那么请考虑将此HashMap保留在其他地方,每当用户使用类似的ListViews在不同活动之间切换时,它就不会重新加载。

使用相同的图片处理多项活动

关于活动,它取决于您如何存储图像。如果它们也从Internet下载并缓存在磁盘上,则可以执行与此答案的ListView部分中所述相同的操作。只需保存已加载到内存中的图像列表并使用

imageView.setImageBitmap(someBitmap)

当您需要在活动的特定部分显示它时。

如果您正在使用应用程序资源,则更容易,因为您可以执行以下操作:

Drawable dr = context.resources.getDrawable(R.drawable.my_favourite_image);
imageView.setImageDrawable(dr);

所有使用内存效率的工作都在这里完成。

如何避免下载相同图片但使用缓存

这取决于您如何跟踪每个图像的唯一性。例如。如果每个图像都有唯一的URL,那么最基本的解决方案是使用带有图像URL的HashMap作为关键字。

更复杂但更灵活和正确的决定是使用Guava缓存工具之类的东西。这不是特定于机器人的,在这个答案中涵盖的主题很广泛,但你可以take a look here

但是,如果您计划弄乱图像的复杂布局并关注性能,请检查Ankothis benchmark。这与内容缓存无关,但布局渲染性能可提高3倍甚至更多。