Android GridView 导致延迟
Android GridView causing lagg
我目前正在开发一个文件共享应用程序。我创建了一个 GridView,我想在其中列出带有缩略图的已下载文件。为此,我使用了自定义适配器。它加载正常,一切都可见,看起来很完美。
技巧如下:加载视图后,我的自定义适配器的 getView 方法在位置 0 上被调用了很多次,导致大量延迟,使用率约为 12% CPU在我的 Xperia XZ Premium 上。
我已经阅读了有关 GridView 中滞后的答案,但在那些情况下,它是由滚动引起的。在我的情况下,不需要滚动,目前 GridView 中只有 1 个项目,但它仍在挣扎。
在滞后的同时,它还会发送垃圾邮件。如果我将以下代码行添加到我的 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 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 7) 之后,我没有设法得到关于 maxLineHeight 的消息,但我可以确认 [=11= 没有结束] 被调用。
此行为的原因是每次执行 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;
}
});
我目前正在开发一个文件共享应用程序。我创建了一个 GridView,我想在其中列出带有缩略图的已下载文件。为此,我使用了自定义适配器。它加载正常,一切都可见,看起来很完美。
技巧如下:加载视图后,我的自定义适配器的 getView 方法在位置 0 上被调用了很多次,导致大量延迟,使用率约为 12% CPU在我的 Xperia XZ Premium 上。
我已经阅读了有关 GridView 中滞后的答案,但在那些情况下,它是由滚动引起的。在我的情况下,不需要滚动,目前 GridView 中只有 1 个项目,但它仍在挣扎。
在滞后的同时,它还会发送垃圾邮件。如果我将以下代码行添加到我的 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 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 7) 之后,我没有设法得到关于 maxLineHeight 的消息,但我可以确认 [=11= 没有结束] 被调用。
此行为的原因是每次执行 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;
}
});