3

Какая из лучших практик для обработки Spinner в адаптере RecyclerView?Как использовать Spinner в 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; 
    } 
} 
} 

и это мой 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, как я могу справиться с этим?

Заранее спасибо.

ответ

12

Short

Для повышения производительности,

  1. Удалить ассигнования из onBindViewHolder
  2. Повторное использование LayoutInflater, вместо получения нового каждый раз.
  3. Минимизация повторяющуюся работу в onBindViewHolder реализации
  4. Spinner адаптер должен также перерабатывают мнения

фон

При использовании адаптера для прокрутки, самое главное, чтобы убедиться, заключается в том, что мы делаем . НЕ ДЕЛАЕМ выделить новые объекты (или свести к минимуму его).

Вся цель 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 каждый раз. Это пустая трата. Лучше получить его в конструкторе адаптера и сохранить его как члена.

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 адаптер должен также перерабатывают мнения

В CartSpinnerAdapter.getView() вы также выделяющие память. Это случается (каждый раз при подсчете * списка элементов) - Это много распределений. Вместо этого используйте convertView. Посмотрите на этот учебник dzone.com/articles/android-listview-optimizations

+0

Привет, спасибо за ответ. Я испытываю проблему с задержкой, так как я добавил логику адаптера к счетчику и даже с этими улучшениями проблема с задержкой не решит. Итак, мой реальный вопрос: как я могу использовать адаптер спрямля внутри адаптера recycliewiew? – Bronx

+0

См. Мое редактирование в разделе (1). –

+1

Также примените предложения к CartSpinnerAdapter. Там вы не используете адаптер правильно, так как вы не перерабатываете представления. Используйте convertView. –

 Смежные вопросы

  • Нет связанных вопросов^_^