标签:android android-spinner android-recyclerview
哪个是在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的适配器的方式,我该如何处理?
提前致谢.
解决方法:
短
为了提高性能,
>从onBindViewHolder中删除分配
>重复使用LayoutInflater,而不是每次都获得一个新的.
>尽量减少onBindViewHolder实现中的重复性工作
> Spinner Adapter还应该回收视图
背景
使用适配器进行滚动时,最重要的是确保我们不分配新对象(或尽可能减少它).
带有适配器的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个直接分配(新)和一些间接分配(膨胀).更改此代码,以便所有分配都在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中绑定相关数据,如下所示:
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还应该回收视图
在CartSpinnerAdapter.getView()中,您还分配内存.它发生(每次*列表项*计数) – 这是很多分配.请改用convertView.看看这个教程dzone.com/articles/android-listview-optimizations
标签:android,android-spinner,android-recyclerview 来源: https://codeday.me/bug/20190713/1449135.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。