gpt4 book ai didi

android - 如何在 Recyclerview 中使用 Spinner?

转载 作者:太空宇宙 更新时间:2023-11-03 11:31:28 25 4
gpt4 key购买 nike

RecyclerView 适配器中处理 Spinner 的最佳实践是什么?

这是我的RecyclerView 适配器:

public class CartAdapter extends BaseAdapter<Object> {

public CartAdapter(AbstractBaseActivity activity) {
super(activity);
}

public static final int TYPE_PRODOTTO = 1;
public static final int TYPE_SCONTO = 2;

@Override
public int getItemViewType(int position) {

if (items.get(position) instanceof Article)
return TYPE_PRODOTTO;
else
return TYPE_SCONTO;
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View rowView = LayoutInflater.from(parent.getContext()).inflate(viewType == TYPE_PRODOTTO ? R.layout.item_cart : R.layout.item_cart_sconto, parent, false);
return new ViewHolder(rowView);
}

@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final ViewHolder viewHolder = (ViewHolder) holder;

final Object object = items.get(position);

if (object instanceof Article) {

viewHolder.getBinding().setVariable(BR.article, object);
viewHolder.getBinding().executePendingBindings();

assert viewHolder.quantitySpinner != null;
assert viewHolder.cartoneQuantity != null;
assert viewHolder.cartoneValue != null;

CartSpinnerAdapter adapter = (CartSpinnerAdapter) viewHolder.quantitySpinner.getAdapter();
adapter.clear();
adapter.setCount(((Article) object).getQuantityAvailable());
adapter.notifyDataSetChanged();

viewHolder.quantitySpinner.setSelection(((Article) object).getQuantity() - 1); //In teoria qui la quantità non deve mai essere zero

viewHolder.cartoneQuantity.setVisibility(position % 2 == 1 ? View.GONE : View.VISIBLE); //Controllo da togliere in futuro
viewHolder.cartoneValue.setVisibility(position % 2 == 1 ? View.GONE : View.VISIBLE); //Controllo da togliere in futuro
}

final PopupMenu popup = new PopupMenu(getContext(), viewHolder.deleteMenu);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.delete_menu, popup.getMenu());

viewHolder.deleteMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
popup.show();
}
});

popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.action_delete) {
removeData(holder.getAdapterPosition());
((CartActivity) activity).checkIfEmpty();
}

return true;
}
});
}

public class ViewHolder extends RecyclerView.ViewHolder {

@BindView(R.id.item)
View item;
@Nullable
@BindView(R.id.cart_image)
ImageView cartImage;
@BindView(R.id.delete_menu)
ImageView deleteMenu;
@Nullable
@BindView(R.id.product_cartone_quantity)
TextView cartoneQuantity;
@Nullable
@BindView(R.id.product_cartone_value)
TextView cartoneValue;
@Nullable
@BindView(R.id.quantity_spinner)
AppCompatSpinner quantitySpinner;

private ViewDataBinding binding;

public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
binding = DataBindingUtil.bind(itemView);
if (quantitySpinner != null)
quantitySpinner.setAdapter(new CartSpinnerAdapter(itemView.getContext(), R.layout.support_simple_spinner_dropdown_item));
}

public ViewDataBinding getBinding() {
return binding;
}
}
}

这是我的 Spinner 适配器:

public class CartSpinnerAdapter extends ArrayAdapter<String> {

LayoutInflater inflater;

int count;

public CartSpinnerAdapter(Context context, int resource) {
super(context, resource);

inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

public CartSpinnerAdapter(Context context, int resource, int count) {
super(context, resource);

this.count = count;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

public void setCount(int count) {
this.count = count;
}

@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getStandardView(position, parent, true);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
return getStandardView(position, parent, false);
}

@Override
public int getCount() {
return count;
}

private View getStandardView(int position, ViewGroup parent, boolean dropdown) {
View row = inflater.inflate(R.layout.support_simple_spinner_dropdown_item, parent, false);

TextView title = (TextView) row.findViewById(android.R.id.text1);

title.setText(String.valueOf(position + 1));

if (dropdown)
title.setMinWidth(Utils.dpToPx(getContext(), 64));
else
title.setAlpha(0.5f);

return row;
}
}

通过这种方式,当我滚动 RecyclerView 时,我遇到了延迟。

如果我删除这些行,一切正常:

CartSpinnerAdapter adapter = (CartSpinnerAdapter) viewHolder.quantitySpinner.getAdapter();
adapter.clear();
adapter.setCount(((Article) object).getQuantityAvailable());
adapter.notifyDataSetChanged();

所以问题是我处理 Spinner 适配器的方式,我该如何处理?

提前致谢。

最佳答案

为了提高性能,

  1. onBindViewHolder 中删除分配
  2. 重复使用 LayoutInflater,而不是每次都获取一个新的。
  3. 最大限度地减少onBindViewHolder实现中的重复性工作
  4. Spinner Adapter 也应该回收 View

背景

当使用适配器进行滚动时,最重要的是要确保我们不要分配新对象(或尽可能减少它)。

带有适配器的 RecyclerView 的全部目的是确保我们回收我们的对象,以便滚动期间所需的工作最少。

由于分配内存非常“昂贵”,要提高滚动性能,首先要寻找的是 onBindViewHolder 期间的分配。所有分配(如果有)都应在 onCreateViewHolder 中进行。

一旦所有分配都被清除,如果我们仍然滞后,是时候进行一些微改进了。其中包括提高代码质量、重用逻辑结果等。

怎么办?

1) 从 onBindViewHolder 中移除分配

在下面的代码中:

final PopupMenu popup = new PopupMenu(getContext(), viewHolder.deleteMenu);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.delete_menu, popup.getMenu());

viewHolder.deleteMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
popup.show();
}
});

popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.action_delete) {
removeData(holder.getAdapterPosition());
((CartActivity) activity).checkIfEmpty();
}

return true;
}
});

您目前有 3 个直接分配()和一些间接分配(inflate)。更改此代码,以便所有分配都在 onCreateViewHolder 中。例如:

onCreateViewHolder 中执行如下分配:

// Allocate Listener only ONCE per recycled view 
viewHolder.deleteMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Get needed data from the view TAG, we will set it later
final int itemPosition = (Integer)view.getTag();

// Do work only when needed - when user clicked the button
final PopupMenu popup = new PopupMenu(getContext(), viewHolder.deleteMenu);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.delete_menu, popup.getMenu());

popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
// Do logic using itemPosition etc
return true;
}
});

popup.show();
}
});

onBindViewHolder中像这样绑定(bind)相关数据:

viewHolder.deleteMenu.setTag(holder.getAdapterPosition());

2) 重复使用 LayoutInflater,而不是每次都获取一个新的。

在下面的代码中:

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View rowView = LayoutInflater.from(parent.getContext()).inflate(viewType == TYPE_PRODOTTO ? R.layout.item_cart : R.layout.item_cart_sconto, parent, false);
return new ViewHolder(rowView);
}

你每次都会得到一个新的 LayoutInflater。这是一种浪费。最好在 Adapter 构造函数中获取一个并将其保存为成员。

3) 尽量减少onBindViewHolder实现中的重复工作

例如,在下面的代码中:

viewHolder.cartoneQuantity.setVisibility(position % 2 == 1 ? View.GONE : View.VISIBLE); //Controllo da togliere in futuro
viewHolder.cartoneValue.setVisibility(position % 2 == 1 ? View.GONE : View.VISIBLE); //Controllo da togliere in futuro

您正在计算相同的逻辑两次。最好计算一次并重用结果:

int cartoneVisibility = position % 2 == 1 ? View.GONE : View.VISIBLE;
viewHolder.cartoneQuantity.setVisibility(cartoneVisibility); //Controllo da togliere in futuro
viewHolder.cartoneValue.setVisibility(cartoneVisibility); //Controllo da togliere in futuro

4)Spinner Adapter 也应该回收 View

CartSpinnerAdapter.getView() 中,您还分配了内存。它发生了(每次 * 列表项 * 计数)——这是很多分配。请改用 convertView。看看这个教程dzone.com/articles/android-listview-optimizations

关于android - 如何在 Recyclerview 中使用 Spinner?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38762010/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com