我正在学习Android,并关注自定义ListView
项目的this教程。
然而,我已经创建了自己的ListView项目,当我加载应用程序时(在我的Galaxy S4,物理设备上)它变得非常慢。
当我使用simple_list_item_1
作为我的列表视图时,一切都运行顺畅,但是当我使用自己的自定义项时,它运行得非常慢。我不明白为什么会这样。似乎没有我创建的昂贵(并且绝对不是无限运行)操作。
我也注意到即使我只有5个listItem,getView方法也会被调用15次左右。对此原因的解释也是受欢迎的。 (他们可能有关系)
对于我的活动,我使用了Android Studio(1.2.2)标准“导航抽屉活动”。我只是在onCreateView方法中添加了东西。现在看起来像这样:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
/* Start of my custom code */
//Create some list items
String[] words = {"Defenestration", "Indicative", "Executive", "Developmental", "Consciousness"};
//The list in the Fragment
ListView list = (ListView) rootView.findViewById(R.id.mainList);
//The custom ListAdapter
ListAdapter la = new ShaggyAdapter(getActivity(), words);
//A built in listadapter for testing
//ListAdapter la2 = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, words);
list.setAdapter(la);
//Create listener
list.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String word = String.valueOf(parent.getItemAtPosition(position));
Toast.makeText(getActivity(), word, Toast.LENGTH_SHORT).show();
}
});
/* End of my custom code */
return rootView;
}
自定义适配器如下所示:
class ShaggyAdapter extends ArrayAdapter<String>{
private static final String TAG = "coo";
public ShaggyAdapter(Context context, String[] words) {
super(context, R.layout.shaggy_item, words);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(getContext());
if (convertView == null){
convertView = inflater.inflate(R.layout.shaggy_item, parent, false);
Log.i(TAG, "inflate");
}else{
Log.i(TAG, "Don't inflate");
}
String word = getItem(position);
TextView name = (TextView) convertView.findViewById(R.id.itemName);
name.setText(word);
return convertView;
}
}
自定义列表项如下所示:
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:columnCount="5">
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:id="@+id/itemImage"
android:layout_row="0"
android:layout_column="0"
android:src="@drawable/no_profile"
android:layout_margin="8dp"
android:layout_rowSpan="2"
android:contentDescription="@string/shaggy_item_image_description" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/shaggy_item_name_placeholder"
android:id="@+id/itemName"
android:layout_row="0"
android:layout_column="1"
android:layout_margin="8dp"
android:layout_marginTop="14dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/shaggy_item_new_tag"
android:id="@+id/itemNew"
android:layout_row="0"
android:layout_column="2"
android:layout_marginTop="14dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/shaggy_item_date_placeholder"
android:id="@+id/itemDate"
android:layout_row="1"
android:layout_column="1"
android:layout_margin="8dp"
android:layout_columnSpan="2" />
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:id="@+id/itemStar"
android:layout_row="0"
android:layout_column="3"
android:src="@drawable/rating_star_1"
android:layout_margin="8dp"
android:layout_marginTop="14dp"
android:layout_rowSpan="2"
android:contentDescription="@string/shaggy_item_star_description" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/shaggy_item_rating_placheholder"
android:id="@+id/itemRating"
android:layout_row="0"
android:layout_column="4"
android:layout_margin="8dp"
android:layout_marginTop="14dp"
android:layout_rowSpan="2" />
</GridLayout>
任何建议都将受到高度赞赏。
答案 0 :(得分:1)
我找到了答案,我犯了一个非常愚蠢的错误。我在配置文件图像视图中使用的图像是2000x2000px,我在80x80dp的imageview中显示它。我注意到内存使用率突然增加了一倍。
使用较小的图像(目前为300x300px)使一切运行得非常流畅。我今天学到的东西:
- 使用正确尺寸的图片! Android并不喜欢处理图片。
我也会按照 Boss 和群众之王的建议使用保持模式,以使其更加流畅。
答案 1 :(得分:1)
为什么findViewById这么慢?为什么View Holder 模式更快?
当你不使用Holder时,getView()方法会多次调用findViewById(),因为你的行将不在View中。因此,如果List中有1000行,而990行将不在View中,则990次将再次被称为findViewById()。
Holder设计模式用于View缓存 - Holder(任意)对象保存每行的子窗口小部件,当行超出View时,将不会调用findViewById()但View将被回收并且将从中获取窗口小部件支架
if (convertView == null) {
convertView = inflater.inflate(layout, null, false);
holder = new Holder(convertView);
convertView.setTag(holder); // setting Holder as arbitrary object for row
}
else { // view recycling
// row already contains Holder object
holder = (Holder) convertView.getTag();
}
// set up row data from holder
titleText.setText(holder.getTitle().getText().toString());
Holder类看起来像:
public class Holder {
private View row;
private TextView title;
public Holder(View row) {
this.row = row;
}
public TextView getTitle() {
if (title == null) {
title = (TextView) row.findViewById(R.id.title);
}
return title;
}
}
以下是如何使用ViewHolder模式的第二种方法:
ViewHolder holder;
// view is creating
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.row, parent, false);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.title);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
}
// view is recycling
else {
holder = (ViewHolder) convertView.getTag();
}
// set-up row
final MyItem item = mItems.get(position);
holder.title.setText(item.getTitle());
...
private static class ViewHolder {
public TextView title;
public ImageView icon;
}
这个Android listview using ViewHolder将帮助您实现相同的目标。
众所周知,Google和AppCompat v7作为支持库发布了名为RecyclerView的新ViewGroup,旨在呈现任何基于适配器的视图。
干杯!!