我有一个 ListView
,它很复杂,因为可能存在 4 种 View 类型的场景,例如{ 书籍、电影、音乐 CD、音乐会 }
目前,为了决定膨胀什么对象等,我得到了与列表行相关的项目。然后,我将在对象的类型字段上执行 switch()
。
这让我在 getView()
中有很多代码和繁重的工作。
我说 getItemViewType()
用于返回当前项目的正确 View 类型是否正确?
我在哪里可以找到使用这种方法的 ListAdapter
示例?注意:这是为了让我的 ListView
变得平滑,它现在非常缓慢。
谢谢
编辑:我的适配器
public class MyListAdapter extends BaseAdapter implements ListAdapter {
private Context ctx;
private int layoutResourceId;
private ArrayList<ItemType> items;
public MyListAdapter(Context context, ArrayList<ItemType> data) {
this.layoutResourceId = R.layout.timeline_item_row;
this.ctx = context;
this.setitems(data);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
TimelineHolder holder = null;
ItemType transaction = getitems().get(position);
if (row == null) {
LayoutInflater inflater = ((Activity) ctx).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new TimelineHolder();
holder.imgActivityIcon = (ImageView)row.findViewById(R.id.imgActivityImageIcon);
holder.imgActivityLabel = (ImageView)row.findViewById(R.id.imgActivityImageLabel);
holder.lblMerchantName = (TextView)row.findViewById(R.id.lblMerchantName);
holder.lblLocation = (TextView)row.findViewById(R.id.lblLocation);
holder.lblActivityType = (TextView)row.findViewById(R.id.lblActivityType);
holder.lblActivityLabelUpper = (TextView)row.findViewById(R.id.lblActivityTypeLabel);
holder.lblTimeSinceActivity = (TextView)row.findViewById(R.id.lblTimeSinceActivity);
holder.lblActivityAmount = (TextView)row.findViewById(R.id.lblActivityAmount);
row.setTag(holder);
}
else {
holder = (TimelineHolder) row.getTag();
}
// Get/Populate common values here
String address = "";
Date hostTime = Helper.parse8601UTC(transaction.getCurrentHostTime());
Date transactionTime = Helper.parse8601UTC(transaction.getHostTransactionTime());
String merchantName = transaction.getMerchant().getName();
holder.lblMerchantName.setText(merchantName);
holder.lblLocation.setText(address);
holder.lblTimeSinceActivity.setText(Helper.timeSince(transactionTime, hostTime));
holder.lblActivityAmount.setText(Helper.doubleToCurrency(transaction.getAmount(), transaction.getCurrency()));
switch (transaction.getTransactionTypeId()) {
case TYPE_ONE:
holder.imgActivityIcon.setImageResource(R.drawable.redemmedicon_2x);
holder.imgActivityLabel.setImageResource(R.drawable.earned_flag);
holder.lblActivityType.setText(R.string.Loyalty_Earned);
holder.lblActivityLabelUpper.setText(R.string.EARNED);
holder.lblActivityAmount.setText(transaction.getResponsePoints() + " pts");
break;
case TYPE_TWO:
holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x);
holder.imgActivityLabel.setImageResource(R.drawable.earned_flag);
holder.lblActivityType.setText(R.string.Prepay_Redeem_Refund);
holder.lblActivityLabelUpper.setText(R.string.REDEEMED);
break;
case TYPE_THREE:
holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x);
holder.imgActivityLabel.setImageResource(R.drawable.earned_flag);
holder.lblActivityLabelUpper.setText(R.string.REFUND);
holder.lblActivityType.setText(R.string.Prepay_Purchase_Refund);
break;
case TYPE_FOUR:
holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x);
holder.imgActivityLabel.setImageResource(R.drawable.earned_flag);
holder.lblActivityLabelUpper.setText(R.string.REFUND);
holder.lblActivityType.setText(R.string.Prepay_Deposit_Refund);
break;
case TYPE_FIVE:
holder.imgActivityIcon.setImageResource(R.drawable.reward_earned_icon_2x);
holder.imgActivityLabel.setImageResource(R.drawable.earned_flag);
holder.lblActivityType.setText(R.string.Reward_Redeemed);
holder.lblActivityLabelUpper.setText(R.string.REDEEMED);
holder.lblActivityAmount.setText("");
break;
case TYPE_SIX:
holder.imgActivityIcon
.setImageResource(R.drawable.reward_earned_icon_2x);
holder.imgActivityLabel.setImageResource(R.drawable.redeemed_flag);
holder.lblActivityType.setText(R.string.Points_Redeemed);
holder.lblActivityLabelUpper.setText(R.string.REDEEMED);
holder.lblActivityAmount.setText(transaction.getResponsePoints()
+ " pts");
break;
case TYPE_SEVEN:
holder.imgActivityIcon.setImageResource(R.drawable.stamp_2x);
holder.imgActivityLabel.setImageResource(R.drawable.redeemed_flag);
holder.lblActivityType.setText(R.string.Checked_In);
holder.lblActivityLabelUpper.setText(R.string.CHECK_IN);
holder.lblActivityAmount.setText("");
break;
case TYPE_EIGHT:
holder.imgActivityIcon.setImageResource(R.drawable.shared_icon_2x);
holder.imgActivityLabel.setImageResource(R.drawable.redeemed_flag);
holder.lblActivityType.setText(R.string.Shared_Coupon);
holder.lblActivityLabelUpper.setText(R.string.SHARED);
holder.lblActivityAmount.setText("");
break;
case TYPE_NINE:
holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x);
holder.imgActivityLabel.setImageResource(R.drawable.earned_flag);
holder.lblActivityType.setText(R.string.Prepay_Deposit);
holder.lblActivityLabelUpper.setText(R.string.DEPOSIT);
break;
case TYPE_TEN:
holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x);
holder.imgActivityLabel.setImageResource(R.drawable.redeemed_flag);
holder.lblActivityType.setText(R.string.Prepay_Purchase);
holder.lblActivityLabelUpper.setText(R.string.PURCHASE);
break;
case TYPE_ELEVEN:
holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x);
holder.imgActivityLabel.setImageResource(R.drawable.earned_flag);
holder.lblActivityType.setText(R.string.Prepay_Redeemed);
holder.lblActivityLabelUpper.setText(R.string.REDEEMED);
break;
case TYPE_TWELVE:
holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x);
holder.imgActivityLabel.setImageResource(R.drawable.earned_flag);
holder.lblActivityType.setText(R.string.Refund);
holder.lblActivityLabelUpper.setText(R.string.REFUND);
holder.lblActivityAmount.setText("");
break;
case TYPE_THIRTEEN:
holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x);
holder.imgActivityLabel.setImageResource(R.drawable.earned_flag);
holder.lblActivityType.setText(R.string.reversal);
holder.lblActivityLabelUpper.setText(R.string.REVERSAL);
holder.lblActivityAmount.setText("");
break;
case TYPE_FOURTEEN:
holder.imgActivityIcon.setImageResource(R.drawable.unlocked_2x);
holder.imgActivityLabel.setImageResource(R.drawable.earned_flag);
holder.lblActivityType.setText(R.string.Check_In_Reward_Unlocked);
holder.lblActivityLabelUpper.setText(R.string.UNLOCKED);
holder.lblActivityAmount.setText("");
break;
case TYPE_FIFTEEN:
holder.imgActivityIcon.setImageResource(R.drawable.reward_earned_icon_2x);
holder.imgActivityLabel.setImageResource(R.drawable.earned_flag);
holder.lblActivityType.setText(R.string.Coupon_Received);
holder.lblActivityLabelUpper.setText(R.string.RECEIVED);
holder.lblActivityAmount.setText("");
break;
default:
holder.imgActivityIcon.setImageResource(R.drawable.stamp_2x);
holder.imgActivityLabel.setImageResource(R.drawable.earned_flag);
holder.lblActivityType.setText("");
holder.lblActivityLabelUpper.setText("");
holder.lblActivityAmount.setText("");
break;
}
return row;
}
@Override
public int getCount() {
return getitems() == null ? 0 : getitems().size();
}
@Override
public Object getItem(int position) {
return getitems() == null ? null : getitems().get(
position);
}
@Override
public long getItemId(int position) {
return layoutResourceId;
}
public void addItem(ItemType item, boolean addFirst) {
if (addFirst) {
getitems().add(0, item);
} else {
getitems().add(item);
}
notifyDataSetChanged();
}
public ArrayList<ItemType> getitems() {
return items;
}
public void setitems(ArrayList<ItemType> items) {
this.items = items;
}
public int getFirstTransactionId() {
int result = 0;
if (items != null && !items.isEmpty()) {
ItemType txn = items.get(0);
result = txn.getId();
}
return result;
}
public int getLastTransactionId() {
int result = 0;
if (items != null && !items.isEmpty()) {
ItemType txn = items.get(items.size() - 1);
result = txn.getId();
}
return result;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public int getItemViewType(int position) {
return 0;
}
}
最佳答案
*** 更新提示 ****
您没有正确实现 getViewTypeCount() 和 getItemViewType()。
阅读我在下面的链接中提供的教程。我不想重新解释它们,因为我会做得更糟。但请先阅读下文,因为您实际上并不需要它,因为您只有一种 View 类型。
选项 1:使用正确的资源图像创建 16 个不同的行。然后在 getView() 方法中调用 getItemViewType(position)。在它上面做一个开关,并根据它返回的 View 类型膨胀正确的行。 (教程将对此进行解释)。这样您就不必一直调用“setImageResource”调用,这很昂贵。
选项 2:根据您的 View 持有者,看起来您只有 1 个 View ,您只是更改 3 个文本字段和 2 个位图。但是每次位图调用都很重,你需要创建一个HashMap来缓存那些图标。每次调用时,引用 HashMap ,如果该项目不存在,则创建它,添加它,然后继续。这很重要,因为每次调用 setImageResource() 都在进行位图解码,并且需要时间。 这才是真正的错误所在请参阅下面的伪代码。
private static HashMap<Integer, Bitmap> cache;
static class BitmapCache {
public static Bitmap get(Integer id) {
if (cache.containsKey(id)) {
return cache.get(id);
} else {
Bitmap t = BitmapFactory.decodeResource(getContext(), id);
cache.put(key, t);
return t;
}
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder item = null;
Object o = getItem(position);
View mRow = convertView;
if (mRow == null) {
LayoutInflater li = LayoutInflater.from(getContext());
switch (getItemViewType(position)) {
case VIEW_ONLINE:
mRow = li.inflate(R.layout.row_online, parent, false);
break;
default:
// default to sortable
mRow = li.inflate(R.layout.row_offline, parent, false);
break;
}
item = new ViewHolder(mRow);
mRow.setTag(item);
} else {
item = (ViewHolder) mRow.getTag();
}
item.icon.setImageBitmap(BitmapCache.get(object.key));
return mRow;
}
* 带教程的旧答案 *
我昨天刚刚浏览的 StackOverflow 上已经有几篇与此相关的帖子。 (见下面的链接)。
- 是的,使用 getItemViewType() 检索正确的 View 类型。据我了解,这里的真正好处在于 getView() 调用期间的 View 优化。实现 getItemViewType() 允许 getView() 类型返回正确的缓存 View 。
- 在膨胀 View 中对文本和 ImageView 使用静态 View 持有者模式。 您不应该每次都膨胀 View ,您应该重复使用 getView() 调用提供的 convertView。
- 一定要实现 getViewTypeCount()
这是一个深入解释如何执行自定义 ListView (包括优化)的教程。 http://www.vogella.com/articles/AndroidListView/article.html
这里有两个 stackoverflow 帖子,它们也讨论了您正在尝试做的事情:
1. Android Programming tutorials - Tutorial 5
2. Restaurant Program Tutorial
关于android - ListView getItemViewType() 的复杂示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15277164/