45

Я создаю список карт для отображения с помощью RecyclerView, где каждая карта имеет кнопку для удаления этой карты из списка.using notifyItemRemoved или notifyDataSetChanged с RecyclerView в Android

Когда я использую notifyItemRemoved(), чтобы удалить карту в RecyclerView, она удаляет элемент и анимирует изображение, но данные в списке не обновляются правильно.

Если вместо этого, я переключаюсь на notifyDataSetChanged(), тогда элементы в списке удаляются и обновляются правильно, но тогда карты не ожидают.

У кого-то есть опыт использования функции notifyItemRemoved() и знаете, почему он ведет себя иначе, чем notifyDataSetChanged?

Вот некоторые peiece кода, который я использую:

private List<DetectedIssue> issues = new ArrayList<DetectedIssue>(); 

@Override 
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 
    // - get element from your dataset at this position 
    // - replace the contents of the view with that element 
    if(position >0){ 
     RiskViewHolder riskHolder = (RiskViewHolder)holder; 
     final int index = position - 1; 
     final DetectedIssue anIssue = issues.get(index); 

     riskHolder.button.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       try { 
        int index = issues.indexOf(anIssue); 
        issues.remove(anIssue); 
        notifyItemRemoved(index); 

        //notifyDataSetChanged(); 
       } catch (SQLException e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 
} 

@Override 
public int getItemCount() { 
    return (issues.size()+1); 
} 
+2

попробовать notifyItemRemoved (индекс + 1) – pskink

+0

Вероятно потому, что вы удаление разных индексов –

+1

Указатель верен. Как я сказал, все работает нормально, если я использую notifyDataSetChanged() вместо этого ..... – revolutionary

ответ

1

Как @pskink предположил, что это должно было быть (индекс + 1) в моем случае с notifyItemRemoved(index+1), вероятно, потому, что я резервируя верхний индекс т.е. position=0 для заголовка.

-2

Вы должны добавить удалить слушателя в классе ViewHolder

button.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 

        onCancel(getAdapterPosition()); 

      } 
     }); 

    private void onCancel(int position) { 
     if (position >= issues.size()) 
      return; 
     issues.remove(position); 
     notifyItemRemoved(position); 
    } 
61

Использование notifyItemRangeChanged (положение, getItemCount()); после notifyItemRemoved (position);
Вам не нужно использовать индекс, просто используйте позицию. См. Код ниже.

private List<DetectedIssue> issues = new ArrayList<DetectedIssue>(); 

@Override 
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 
    // - get element from your dataset at this position 
    // - replace the contents of the view with that element 
    if(position >0){ 
     RiskViewHolder riskHolder = (RiskViewHolder)holder; 

     riskHolder.button.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       try { 
        issues.remove(position); 
        notifyItemRemoved(position); 
        //this line below gives you the animation and also updates the 
        //list items after the deleted item 
        notifyItemRangeChanged(position, getItemCount()); 

       } catch (SQLException e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 
} 

@Override 
public int getItemCount() { 
    return issues.size(); 
} 
+0

Из документации: «Вы должны использовать только параметр позиции при получении связанного элемента данных внутри этого метода и не должны сохранять его копию. Если вам понадобится позиция элемента позже (например, в прослушивателе кликов), используйте RecyclerView .ViewHolder.getAdapterPosition(), который будет иметь обновленную позицию адаптера. " –

+0

@Akshay Mahajan Старая нить извините, но 'notifyItemRemoved (position);' работает просто отлично (с анимацией). Что означает 'notifyItemRangeChanged (position, getItemCount());' делает? Я не вижу разницы. Спасибо –

+0

Не должно быть getItemCount() - позиция, поскольку itemCount означает количество элементов после удаленного элемента? –

5

моя ошибка, notifyItemChanged (позиция) беспомощен, элемент позиции могут быть удалены, а элемент позиции + 1 отлично, но элементы начинаются с позиции + 2, вы получите Исключение, используйте notifyItemRangeChanged (position, getItemCount()); после notifyItemRemoved (position);

так:

public void removeData(int position) { 
    yourdatalist.remove(position); 
    notifyItemRemoved(position); 
    notifyItemRangeChanged(position,getItemCount()); 
} 
+1

, пожалуйста, предоставьте подробную информацию о том, что изменится, сделав это и как это поможет решить проблему. – AndroidMechanic

10

Пробовал

public void removeItem(int position) { 
    this.taskLists.remove(position); 
    notifyItemRemoved(position); 
    notifyItemRangeChanged(position, getItemCount() - position); 
} 

и работает как шарм.

0

Вы можете использовать getLayoutPosition() из RecyclerView.ViewHolder

getLayoutPosition() обеспечивает точное положение элемента в макете и код

holder.removeButton.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       //Position for remove 
       int modPosition= holder.getLayoutPosition(); 
       //remove item from dataset 
       numbers.remove(modPosition); 
       //remove item from recycler view 
       notifyItemRemoved(modPosition); 
      } 
     }); 
+0

Вы должны использовать getAdapterPosition как [documentation] (https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html#getLayoutPosition()), вы рискуете создать несогласованности. –

0
**my solution looks like this** 

this way is unnecessary to use the heavy method: 
//notifyItemRangeChanged(xx,xx) 

/** 
* 
* recyclerView的item中的某一个view,获取其最外层的viewParent,也就是item对应的layout在adapter中的position 
* 
* @param recyclerView 
* @param view:can be the deep one inside the item,or the item itself . 
* @return 
*/ 
public static int getParentAdapterPosition(RecyclerView recyclerView, View view, int parentId) { 
    if (view.getId() == parentId) 
     return recyclerView.getChildAdapterPosition(view); 
    View viewGroup = (View) view.getParent(); 
    if (viewGroup != null && viewGroup.getId() == parentId) { 
     return recyclerView.getChildAdapterPosition(viewGroup); 
    } 
    //recursion 
    return getParentAdapterPosition(recyclerView, viewGroup, parentId); 
} 




//wherever you set the clickListener . 
holder.setOnClickListener(R.id.rLayout_device_item, deviceItemClickListener); 
holder.setOnLongClickListener(R.id.rLayout_device_item, deviceItemLongClickListener); 


@Override 
public boolean onLongClick(View v) { 
    final int position = ViewUtils.getParentAdapterPosition(rVDevicesList, v, R.id.rLayout_device_item); 
    return true; 
}