【问题标题】:Android GridView causing laggAndroid GridView 导致延迟
【发布时间】:2018-03-02 20:12:47
【问题描述】:

我目前正在开发一个文件共享应用程序。我创建了一个 GridView,我想在其中列出已下载的带有缩略图的文件。为此,我使用了自定义适配器。它加载良好,一切都可见,看起来很完美。

诀窍如下:加载视图后,我的自定义适配器的 getView 方法在位置 0 上被调用了很多次,这会导致大量滞后,我的 Xperia XZ Premium 上的 CPU 使用率约为 12%。

我已经阅读了有关 GridView 中滞后的答案,但在这些情况下,它是由滚动引起的。在我的情况下,不需要滚动,目前 GridView 中只有 1 个项目,但它仍在挣扎。

在滞后的同时,它还会发送垃圾邮件。如果我将以下代码行添加到我的 TextViews,此消息可能会消失:

android:singleLine="true"

但此属性已被弃用,并不能解决问题,只是消息消失了。

当视图为空时,滞后不存在。

我的适配器的getView方法:

@Override
public View getView(int position, View convertView, @NonNull ViewGroup parent){
    View listItem = convertView;
    if(listItem==null){
        listItem = LayoutInflater.from(getContext()).inflate(R.layout.downloaded_grid_item, parent, false);
    }

    final Downloaded current = getItem(position);

    final ImageView thumbnail = (ImageView)listItem.findViewById(R.id.downloaded_grid_item_thumb);
    final TextView name = (TextView)listItem.findViewById(R.id.downloaded_grid_item_name);
    final TextView subtext = (TextView) listItem.findViewById(R.id.downloaded_grid_item_subtext);

    thumbnail.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            int width = thumbnail.getMeasuredWidth();
            thumbnail.setLayoutParams(new LinearLayout.LayoutParams(width, width));
            return true;
        }
    });

    listItem.setTag(position);
    thumbnail.setTag(position);
    name.setTag(position);
    subtext.setTag(position);

    name.setText(current.getName());
    subtext.setText(DateFormat.getDateInstance().format(new Date(current.getTime())));
    thumbnail.setImageBitmap(ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(current.getPath()), 400, 400));

    return listItem;
}

GridView:

<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/downloaded_grid_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="90dp"
android:numColumns="auto_fit"
android:layout_margin="10dp"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"/>

项目的自定义布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/downloaded_grid_item"
android:background="@drawable/downloaded_grid_item_background"
android:orientation="vertical"
android:padding="4dp"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ImageView
    android:id="@+id/downloaded_grid_item_thumb"
    android:layout_width="match_parent"
    android:layout_height="90dp"
    android:src="@drawable/ic_menu_gallery"
    android:scaleType="centerInside"/>

<TextView
    android:id="@+id/downloaded_grid_item_name"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textStyle="bold"
    android:textAppearance="@style/TextAppearance.AppCompat.Small"
    tools:text="name"
    android:ellipsize="end"
    android:lines="1"/>
<TextView
    android:id="@+id/downloaded_grid_item_subtext"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAppearance="@style/TextAppearance.AppCompat.Small"
    tools:text="download date"
    android:ellipsize="end"
    android:lines="1"/>
</LinearLayout>

以及由设备发送的垃圾邮件:

W/StaticLayout: maxLineHeight should not be -1.  maxLines:1 lineCount:1

【问题讨论】:

    标签: android xml android-layout android-gridview


    【解决方案1】:

    在模拟器 (Android 7) 中运行您的代码后,我没有收到有关 maxLineHeight 的消息,但我可以确认 getView() 没有结束被调用。

    这种行为的原因是每次执行 getView() 时,您都会添加一个新的 OnPreDrawListener 而不会删除它。更改ImageView 的高度会强制重新计算它的绘制方式。这会导致整个GridView 经历一个新的布局过程(测量-绘制-布局)。所以getView() 被再次调用(通常对于位置0 至少两次)。因为您永远不会删除 OnPreDrawListener,所以它们都会再次触发,只会导致 CPU 的工作越来越多,而不会实际更改 ImageView 的高度值。

    您需要在获得所需信息后立即删除添加到ViewTreeObserver 的侦听器。所以你需要写

    thumbnail.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            thumbnail.getViewTreeObserver().removeOnPreDrawListener(this);
            int width = thumbnail.getMeasuredWidth();
            thumbnail.setLayoutParams(new LinearLayout.LayoutParams(width, width));
            return true;
        }
    });
    

    【讨论】:

    • 谢谢,它确实解决了我的问题。但是消息仍然存在,但不是垃圾邮件。
    • @Dávid Besenyei - 该消息只是一个警告,因此它可能永远不会成为您的应用程序的问题。您甚至在任何地方都使用 StaticLayout 吗?我只能看到您放置在 LinearLayout 中进行测试的 GridView。就像我说的,我没有在我的设置中看到这条消息。该消息可能来自某些不属于您的活动/片段的组件(例如状态栏)。它可能只出现在某些设备上或使用某些构建工具版本时。 (续)
    • (续)我的建议是:如果您的应用程序正在运行,请忽略警告。如果您遇到问题,请使用足够的代码提出一个新问题以重现该错误,并提及您正在使用的构建工具版本以及(理想情况下)哪些仿真器将显示有问题的行为。即使是现在您也可以考虑提高性能的另一件事:调整 ImageView 的大小会触发布局传递。改变 ImageView 的 padding 只会导致 ImageView 被重绘。因此,也许您可​​以使用最大尺寸的 ImageView 并修改填充以实现缩放动画
    • 我的应用程序现在完美运行。我没有使用任何 StaticLayout,我仍然不知道此消息来自何处,并且仅在 GridView 膨胀时显示。我也忽略了它,因为我的主要问题已经解决了。关于您的其他建议,我会考虑的,非常感谢您的努力。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-23
    • 2014-04-24
    • 1970-01-01
    • 2016-12-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多