我目前正在开发文件共享应用程序。我创建了一个GridView,我想用缩略图列出已经下载的文件。为此,我使用自定义适配器。它加载很好,一切都可见,看起来很完美。
诀窍如下:加载视图后,我的自定义适配器的getView方法在位置0上调用很多次,导致大量滞后,在我的Xperia XZ Premium上占用大约12%的CPU。
我已经在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:
<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的消息,但我可以确认没有调用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;
}
});