Android GridView导致lagg

时间:2018-03-02 20:12:47

标签: android xml android-layout android-gridview

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

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

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

虽然滞后,但它也会发送消息。如果我将以下代码行添加到TextViews中,则此消息可能会消失:

android:singleLine="true"

但是这个属性已被弃用,并没有解决问题,只有消息消失了。

当视图为空时,lagg不存在。

我的适配器的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

1 个答案:

答案 0 :(得分:0)

在模拟器(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;
    }
});