Android ListView 性能

Posted

技术标签:

【中文标题】Android ListView 性能【英文标题】:Android ListView performance 【发布时间】:2015-05-24 00:27:36 【问题描述】:

在我们的 android 应用程序中,我们有一个 ListView,其中填充了不同用户之间的活动聊天会话。用户可以拥有多少活跃的聊天会话并没有真正的限制,因此显然这个 ListView 包含的项目数量也没有限制。

每个 ListView 项目包括:

1 倍放大的 View 包含多张图片 1x 图像视图 1x 字符串

就加载时间以及外观和构图而言,一切都按照我们想要的方式进行。虽然 ListView 包含以下 20 个项目,但一切正常。一旦 ListView 开始包含超过 20 个项目,性能就会逐渐变得越来越难以忍受,因为添加的每个项目。

我一直在做一些试错测试,试图禁用项目结构的每个元素和组件,我发现只要我们有 any em> 项目中的图像类型。因此,无论哪种图像,当 ListView 包含超过 20 个项目时,任何图像都会导致性能下降。我该如何优化呢?我已经从我们的适配器中附加了 getView + 我们添加照片的方法。

感谢任何和所有帮助和/或建议:)

从我们的适配器获取视图:

public View getView(int position, View convertView, ViewGroup parent) 
    System.out.println("getview:"+position+" "+convertView);

    ViewHolder viewHolder;

    Match match = matches.get(position);

    if(convertView==null)
        LayoutInflater inflater = (LayoutInflater) mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.matches_list_item,  parent, false);

        viewHolder = initViewHolder(convertView, match);

     else 

        viewHolder = (ViewHolder) convertView.getTag();
    

    addGroupPhoto(imageSize, match, viewHolder, false);

    if (match.matchedGroup != null) 

        viewHolder.names.setText(match.matchedGroup.getMembersNames());
        viewHolder.matchedText.setText(match.latestMessage.value == null ?
                String.format(mContext.getString(R.string.matched_on), getFormatedMatchDate(match.matchedOn)) : match.latestMessage.value);

    
    return convertView;

从我们的适配器添加GroupPhoto

private void addGroupPhoto(int imageSize, Match match, ViewHolder viewHolder,     boolean isSelected) 

    if (viewHolder.groupPhoto.findViewById(R.id.unseen_messages) != null) 
        viewHolder.groupPhoto.removeView(viewHolder.groupPhoto.findViewById(R.id.unseen_messages));
    

    if (match.matchedGroup != null) 
        RelativeLayout lay = Utilities.createGroupImagePhoto(mContext, imageSize, imageSize, match.matchedGroup.members, Utilities.GROUP_PHOTO_MODE_GROUP_WITHOUT_NAMES);
        ((RelativeLayout.LayoutParams)lay.getLayoutParams()).addRule(RelativeLayout.CENTER_VERTICAL);
        ((RelativeLayout.LayoutParams)lay.getLayoutParams()).addRule(RelativeLayout.ALIGN_LEFT);
        ((RelativeLayout.LayoutParams)lay.getLayoutParams()).setMargins(smallMargin, 0, 0, 0);
        viewHolder.groupPhoto.addView(lay);
        lay.invalidate();
    

    ImageView crop = new ImageView(mContext);
    crop.setBackgroundResource(getCropImageDrawable(isSelected));
    crop.setLayoutParams(new RelativeLayout.LayoutParams(imageSize,imageSize));
    ((RelativeLayout.LayoutParams)crop.getLayoutParams()).addRule(RelativeLayout.CENTER_VERTICAL);
    ((RelativeLayout.LayoutParams)crop.getLayoutParams()).addRule(RelativeLayout.ALIGN_LEFT);
    ((RelativeLayout.LayoutParams)crop.getLayoutParams()).setMargins(smallMargin, 0, 0, 0);

    int marginForMessage = 0;

    viewHolder.groupPhoto.addView(crop);
    if (!match.seen | match.newMessages > 0) 
        addMessages(match.newMessages,  marginForMessage, viewHolder);
    

编辑:这是由以编程方式添加图像引起的。在 XML 文件中添加图像和它们的不同属性之后,而不是添加它们并以编程方式声明它们的参数,一切都很顺利。

【问题讨论】:

当您在视图回收方面做任何正确的事情时,您应该明确考虑使用 Picasso 进行图像加载square.github.io/picasso 在运行时更改布局参数也不是最好的方法 - 像 centerCrop 或 fitCenter 这样的比例类型可以我认为为 imageview 做你的工作 - 你也应该在你的 XML 中有视图,并且只是改变项目的可见性以获得更好的性能,而不是在运行时创建或删除它们 感谢您的建议 - 我们也在考虑优化我们通常如何处理我们的图像。但是,即使使用从我们的资源加载的小型优化 png 文件的单个 ImageView,ListView 中的性能下降仍然存在。我怀疑使用 Picasso(或类似可用的库)会解决我们的性能问题。 我肯定会在 picasso 上试一试 - 也将 imageview 放在 xml 中并将其设置为标准,并且在您将可见性设置为消失或可见之后 - 这也应该有助于改进性能。 是的,我的第一条评论可能很快。现在尝试 Picasso - 也会尝试您的 XML 相关建议。 【参考方案1】:

问题的根源似乎是您正在添加Views 并在您的Adapter 中以编程方式设置它们的LayoutParams。这本质上比在 XML 中设置要“重”,并且在中低端设备上会变得更加明显。

除非您有令人信服的理由以这种方式添加Views,否则您不应该这样做。 Picasso 在这里帮不了你。

注意:我注意到的一件小事是你没有打电话

convertView.setTag(holder);

在您的 getView() 方法中。这种遗漏也可能是性能问题的根源。

【讨论】:

谢谢!删除参数的编程设置修复了它。现在在 XML 文件中包含所有 ImageView - 平滑、平滑的滚动。【参考方案2】:

另外一个考虑因素是,在addGroupPhoto() 中,每个列表项至少多出一个findViewById()

ViewHolder 模式的唯一目的是缓存对视图的引用,即仅在您第一次设置 ViewHolder 时调用findViewById

【讨论】:

以上是关于Android ListView 性能的主要内容,如果未能解决你的问题,请参考以下文章

Android App 在片段中创建 ListView 引用时关闭

Android ListView随手缓慢滑动时有残影现象

如何在app小部件中使用ListView并在android中填充数据?

使用 Kotlin 从 Android 上 ViewModel 中的 LiveData 更新 ListView 中的元素

列表视图--ListView相关类及其适配器

Android:如何让我检索到的(来自 mysql)JSON 解析数据添加到 ListView 每分钟刷新一次