Android 如何在Recyclerview中使用微调器?

Android 如何在Recyclerview中使用微调器?,android,android-recyclerview,android-spinner,Android,Android Recyclerview,Android Spinner,在RecyclerView适配器中处理微调器的最佳实践是什么 这是我的RecyclerView适配器: public class CartAdapter extends BaseAdapter<Object> { public CartAdapter(AbstractBaseActivity activity) { super(activity); } public static final int TYPE_PRODOTTO = 1; public static fin

RecyclerView
适配器中处理微调器的最佳实践是什么

这是我的
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;
    }
}
}
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;
}
}
CartSpinnerAdapter adapter = (CartSpinnerAdapter) viewHolder.quantitySpinner.getAdapter();
adapter.clear();
adapter.setCount(((Article) object).getQuantityAvailable());
adapter.notifyDataSetChanged();
这样,当我滚动
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;
    }
}
}
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;
}
}
CartSpinnerAdapter adapter = (CartSpinnerAdapter) viewHolder.quantitySpinner.getAdapter();
adapter.clear();
adapter.setCount(((Article) object).getQuantityAvailable());
adapter.notifyDataSetChanged();
因此,问题是如何处理
微调器的适配器,如何处理

提前感谢。

Short

为了提高绩效

  • 从onBindViewHolder删除分配
  • 重新使用布局更平坦的布局,而不是每次都得到一个新的布局
  • 尽量减少BindViewHolder实施中的重复工作
  • 微调器适配器也应循环使用视图
  • 背景

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

    带有适配器的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;
        }
    });
    
    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);
    }
    
    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
    
    您目前有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) 重新使用布局更平坦的布局,而不是每次都得到一个新的布局

    在以下代码中:

    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 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);
    }
    
    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
    
    你每次都会得到一个新的工作机会。这是一种浪费。最好在适配器构造函数中获取一个,并将其另存为成员

    3) 尽量减少BindViewHolder实施中的重复工作

    例如,在以下代码中:

    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 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);
    }
    
    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) 微调器适配器也应循环使用视图


    CartSpinnerAdapter.getView()
    中,您也在分配内存。它发生了(每次*列表项*计数)-这是大量的分配。请改用convertView。查看本教程

    您好,感谢您的回复。自从我将适配器逻辑添加到微调器之后,我遇到了滞后问题,即使有了这些改进,滞后问题也无法解决。因此,我真正的问题是,如何在recyclerview适配器中使用微调器适配器?同时,将建议应用于CartSpinnerAdapter。由于未回收视图,因此未正确使用适配器。使用convertView。延迟是由以下行引起的:“CartSpinnerAdapter=(CartSpinnerAdapter)viewHolder.quantitySpinner.getAdapter();adapter.clear();adapter.setCount(((文章)对象)。getQuantityAvailable());adapter.notifyDataSetChanged();”如我所说,在CartSpinnerAdapter中。getView您正在分配内存。每次*列表项*计数时都会发生这种情况-这是一个很大的分配。实际上,您需要0个分配。请改用convertView。看看这个教程@RRR,在本例中,“绑定”是setCount函数。在其他情况下,我们可能有其他绑定。无论如何,最重要的是要记住,我们不应该在UI布局期间快速调用的函数中分配内存。找到分配,把它们拿出来,你就是黄金:)