Ошибка Lint Не рассматривать позицию как фиксированную; использовать только немедленно

Я вношу вклад в библиотеку с открытым исходным кодом и получил ошибку lint "Не рассматривать позицию как фиксированную; используйте только немедленно и вызовитеholder.getAdapterPosition(), чтобы найти ее позже" для этого кода:

  @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    mAdapter.onBindViewHolder(holder, position);

    if (!isFirstOnly || position > mLastPosition) {
      for (Animator anim : getAnimators(holder.itemView)) {
        anim.setDuration(mDuration).start();
        anim.setInterpolator(mInterpolator);
      }
      mLastPosition = position;
    } else {
      ViewHelper.clear(holder.itemView);
    }
  }

Я проверил, что это потому, что позиция сохранена для будущего использования. Вопрос создателям библиотек, зачем им эта логика. Но проблема исчезла, когда я изменил использование позиции на использование holder.getAdapterPosition():

  @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    mAdapter.onBindViewHolder(holder, position);

    if (!isFirstOnly || holder.getAdapterPosition() > mLastPosition) {
      for (Animator anim : getAnimators(holder.itemView)) {
        anim.setDuration(mDuration).start();
        anim.setInterpolator(mInterpolator);
      }
      mLastPosition = holder.getAdapterPosition();
    } else {
      ViewHelper.clear(holder.itemView);
    }
  }

Я предполагаю, что концептуально это не сильно изменилось, но lint теперь доволен. Почему?


person Eugen Martynov    schedule 22.01.2016    source источник
comment
Нет никакой гарантии, что привязка будет вызвана в идеальном порядке, в котором представления элементов действительно видны. Таким образом, mLastPosition может быть не последним видимым элементом.   -  person S.D.    schedule 22.01.2016
comment
Хорошо, это хороший вклад для создателей библиотек, но почему сейчас lint удовлетворяется?   -  person Eugen Martynov    schedule 22.01.2016


Ответы (1)


Документация RecyclerView.Adapter.onBindViewHolder() указывает:

Обратите внимание, что в отличие от ListView, RecyclerView не будет снова вызывать этот метод, если положение элемента изменится в наборе данных, если только сам элемент не станет недействительным или новое положение не может быть определено. По этой причине вы должны использовать параметр position только при получении связанного элемента данных внутри этого метода и не должны сохранять его копию. Если вам понадобится позиция элемента позже (например, в прослушивателе кликов), используйте getAdapterPosition(), который будет иметь обновленную позицию адаптера.

Таким образом, технически элементы могут быть переупорядочены (например, отсортированы или перемещены), и привязка не потребуется, поскольку элементы еще не признаны недействительными. Это означает, что onBindViewHolder() НЕ МОЖЕТ вызываться, если элементы отображают одни и те же данные, но изменяется только их позиция/индекс в списке. Полученная переменная position верна только для области действия функции привязки и не всегда будет указывать на правильную позицию в наборе данных. Вот почему функция getAdapterPosition() должна вызываться каждый раз, когда требуется обновленная позиция.

ИМХО, mLastPosition = holder.getAdapterPosition(); все еще потенциально неправильно. Потому что элемент может быть переставлен, а mLastPosition по-прежнему указывает на старую позицию.

О том, почему lint молчит, возможно, правило Lint не такое тщательное. Это только проверка того, копируется ли параметр position или нет.

person S.D.    schedule 22.01.2016
comment
На самом деле это не работает на сборке Linux, но проходит на Mac. - person Eugen Martynov; 22.01.2016
comment
Тогда почему Google выпускает образцы с кодом, который вызовет эту ошибку lint? - person IgorGanapolsky; 28.01.2016
comment
Странный. Думаю, они что-то планируют. - person Kyle Emmanuel; 05.05.2016
comment
@С.Д. Не могли бы вы уточнить mLastPosition =holder.getAdapterPosition(); по-прежнему потенциально неверен.? Почему это потенциально неправильно? - person Juuso Ohtonen; 03.07.2017
comment
@JuusoOhtonen Потому что элемент может быть переставлен, а mLastPosition по-прежнему указывает на старую позицию при использовании в другом месте. - person S.D.; 03.07.2017
comment
@taurelas Инструмент lint анализирует файлы кода на основе правил. Правила — это программы, которые могут обращаться к исходным конструкциям и искать плохие шаблоны. Вот пример - person S.D.; 12.09.2017
comment
@С.Д. хорошо, так что это специальное правило для сопровождения библиотеки. Спасибо. - person Maciej Beimcik; 12.09.2017