我认为标题中的问题很明确。我不知道如何解释这一点但是对于ListView性能,我尝试了很多东西,例如使用ViewHolder,将Bitmaps保留在列表中并在我的适配器的getView()方法中引用它们,删除每个控件和getView()等中的onClicklistener方法但是根据我的经验,在一个ListItem中使用2个ImageView是可以的,但是当使用3个ImageView时,初始化和滚动都非常慢。
ArrayList<User> users;
Context context;
DatabaseHelper db;
LayoutInflater inflater;
Bitmap defaultImage;
ArrayList<Bitmap> userPhotos;
Bitmap messageImage;
Bitmap callImage;
public FriendsAdapter(Context context){
this.context = context;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
db = new DatabaseHelper(context);
users = db.getFriends();
defaultImage = BitmapFactory.decodeResource(context.getResources(), R.drawable.no_image_small);
userPhotos = new ArrayList<Bitmap>();
for (int i = 0; i < users.size(); i++){
if(users.get(i).getPhoto() != null && !users.get(i).getPhoto().isEmpty()){
userPhotos.add(getCircularCroppedBitmap(stringToBitMap(users.get(i).getPhoto())));
}
else{
userPhotos.add(null);
}
}
messageImage = BitmapFactory.decodeResource(context.getResources(), R.drawable.message);
callImage = BitmapFactory.decodeResource(context.getResources(), R.drawable.call);
}
在这里你可以看到两个来自drawable的图像和一个来自string的图像,但它对于siliding并不重要,因为它们都存储在变量中。
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null){
convertView = inflater.inflate(R.layout.friend_item, parent, false);
holder = new ViewHolder();
holder.imageViewPhoto = (ImageView) convertView.findViewById(R.id.friend_item_photo);
holder.textViewName = (TextView) convertView.findViewById(R.id.friend_item_name);
holder.imageViewMessage = (ImageView) convertView.findViewById(R.id.friend_item_message_photo);
holder.imageViewCall = (ImageView) convertView.findViewById(R.id.friend_item_call_photo);
convertView.setTag(holder);
}
else{
holder = (ViewHolder) convertView.getTag();
}
holder.imageViewMessage.setImageBitmap(messageImage);
//holder.imageViewCall.setImageBitmap(callImage);
User user = users.get(position);
Bitmap photo = userPhotos.get(position);
if(photo == null){
holder.imageViewPhoto.setImageBitmap(defaultImage);
}
else{
holder.imageViewPhoto.setImageBitmap(photo);
}
holder.textViewName.setText(user.getName() + " " + user.getSurname());
return convertView;
}
private static class ViewHolder{
ImageView imageViewPhoto;
TextView textViewName;
ImageView imageViewMessage;
ImageView imageViewCall;
}
在此代码中一切正常。但是当我执行holder.imageViewCall.setImageBitmap(callImage);一切都太慢了。
<ImageView
android:id="@+id/friend_item_photo"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<TextView
android:id="@+id/friend_item_name"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:maxLines="1"
android:gravity="center_vertical"/>
<ImageView
android:id="@+id/friend_item_call_photo"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<ImageView
android:id="@+id/friend_item_message_photo"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
这是我的listItem xml。 linearLayout包含了但我无法在此添加。这是我的第一篇文章。
编辑:它已经是一个基础适配器。
答案 0 :(得分:2)
适配器的构造函数正在主线程上执行 lot 工作。
首先,您正在进行数据库查询,这可能很慢,或者如果另一个线程同时写入数据库,则可能会阻止。
您的数据库代码未发布,但看起来您正在迭代Cursor
并从结果中构建ArrayList
。这很好,但需要时间。如果您直接使用Cursor,则可以在查询完成后立即返回。
您再次迭代所有结果并为每个项目创建一个图像,包括从某处(I / O)加载位图并将其裁剪为圆形。位图操作通常不便宜。此外,您正在为每个项目创建这些图像并将其存储在内存中,但用户可能永远不会看到超过少量项目。如果您总共有一千个项目,并且屏幕上只有10行,那么您现在可以制作990多个图像。用户可能永远不会滚动浏览所有项目,这意味着您浪费了大量工作来查看无法看到的图像。
同样,所有都发生在主线程上。我猜#3是花费大部分时间的地方。
对于问题1和2,您应该学习如何使用Loader
框架或其他异步机制在后台线程上加载数据。通常,Activity或Fragment负责此,而不是适配器本身。它可能仍然需要时间,但它将在后台,因此主线程未被阻止,您可以在等待时在屏幕上显示加载微调器。
对于问题3,您应该使用像Glide或Fresco这样的图像缓存框架。这些库根据需要在后台加载图像并对其进行缓存(这样,如果您需要再次使用相同的图像,如果图像仍然被缓存,它可以跳过加载)。调用getView()
时,开始加载该项目的图像。加载完成后,设置该行的图像 - 通常这些框架会自动执行此操作,您甚至可以指定在加载时显示的默认图像。
答案 1 :(得分:1)
使用图像缓存和加载库,如Glide,Picasso等
使用异步任务加载图像也可以提高性能。
答案 2 :(得分:1)
感谢Guilherme P. &#34;图片大吗?也许,你应该在列表视图中只使用图片的小版本(缩略图)...也许,你可以用非常小的图片进行测试,以检查性能是否得到改善&#34;
这是真正的答案。我忘了调整图片大小。来自字符串的图像很小(125x125)但其他两个图像太大。其中一个是512x512,另一个是1024x1024。我将它们调整为100x100,现在一切都很顺利。这是非常基础的,应该是找到问题的第一种方法,但项目中有很多东西,很多时候忽略了基本的想法。
编辑:感谢您的其他答案,但我在很多活动和片段中完成了这些事情。我知道我在构造函数中做了很多事情,但我必须这样做。项目的其他部分有更复杂的代码,但没有问题。
编辑2:Karakuri也谢谢你。你的答案很好但我的问题并不复杂。当只有6-7项时,我的代码工作缓慢。您的答案适用于数百种商品。我稍后会做的。
答案 3 :(得分:0)
Recycler Views出于这个原因构建的视图。由于您可能对列表视图做了太多,可能会尝试做太多,这可能是导致问题的原因。 https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html