簡體   English   中英

如何在Recyclerview中使用Spinner?

[英]How to use Spinner in 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的適配器的方式,我該如何處理?

提前致謝。

為了提高性能,

  1. onBindViewHolder中刪除分配
  2. 重復使用LayoutInflater ,而不是每次都獲得一個新的。
  3. 最大限度地減少onBindViewHolder實現中的重復性工作
  4. 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM