RecyclerView внутри NedtedScrollView вызывает onCreateViewHolder для каждого элемента

У меня есть случай, когда мне нужно, чтобы RecyclerView было внутри NestedScrollView. Проблема в том, что во время инициализации методы onCreateViewHolder и onBindViewHolder вызывают КАЖДЫЙ элемент в списке (например, 100 элементов).

Так вот нет рециркуляции просмотров на экране и в более сложном случае у меня большие проблемы с производительностью.

Код моего Activity:

public class MyActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final RecyclerView recyclerView = findViewById(R.id.recycler_view);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setAdapter(new MyListAdapter());
}
}

Код моего .xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/refresh"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:nestedScrollingEnabled="false"/>

</android.support.v4.widget.NestedScrollView>
</RelativeLayout>

Код моего адаптера:

public class MyListAdapter extends RecyclerView.Adapter<MyListAdapter.Holder>{

@Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
    final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
    Log.d("TESTING", "onCreate: " + view.hashCode());
    return new Holder(view);
}

@Override
public void onBindViewHolder(Holder holder, int position) {
    Log.d("TESTING", "onBind position: " + position + ", view: " + holder.view.hashCode());
    holder.setContent(position % 2 == 0 ? R.color.colorPrimary : R.color.colorAccent);
}

@Override
public int getItemCount() {
    return 100;
}

class Holder extends RecyclerView.ViewHolder {

    private View view;

    public Holder(View itemView) {
        super(itemView);
        view = itemView;
    }

    public void setContent(int colorRes) {
        view.setBackgroundResource(colorRes);
    }
}
}

И во время инициализации у меня есть эти журналы:

    onCreate: 147045034
    onBind position: 0, view: 147045034
    onCreate: 235006520
    onBind position: 1, view: 235006520
    onCreate: 16439158
    onBind position: 2, view: 16439158
    onCreate: 84373988
    onBind position: 3, view: 84373988
    onCreate: 146076930
    onBind position: 4, view: 146076930
    onCreate: 12306512
    onBind position: 5, view: 12306512
    onCreate: 167862094
    onBind position: 6, view: 167862094
    onCreate: 220010876

    ... logs for items 7 - 94

    onCreate: 189894540
    onBind position: 95, view: 189894540
    onCreate: 121777898
    onBind position: 96, view: 121777898
    onCreate: 38672504
    onBind position: 97, view: 38672504
    onCreate: 210522038
    onBind position: 98, view: 210522038
    onCreate: 243811364
    onBind position: 99, view: 243811364

person Pablo    schedule 24.03.2018    source источник
comment
Взгляните на stackoverflow.com/questions/37322061/   -  person ADM    schedule 24.03.2018
comment
@ADM Я пытался изменить атрибуты android:layout_height, как они сказали в этом ответе, но это не помогает (   -  person Pablo    schedule 24.03.2018


Ответы (2)


У меня была эта проблема раньше, и, судя по моим выводам, невозможно иметь эту настройку и заставить RecyclerView фактически перерабатывать представления.

RecyclerView вычисляет, сколько представлений он должен отображать, спрашивая у родительского представления, насколько оно велико.
ScrollView просит своих дочерних элементов увеличить все свои представления, чтобы он мог вычислить свою собственную высоту и посмотреть, сколько он должен иметь возможность прокручивать. .

Это вызывает конфликты, поэтому это означает, что RecyclerView будет раздувать ВСЕ свои дочерние представления, что в основном делает RecyclerView бесполезным.

Мое исправление заключалось в том, чтобы все элементы были частью RecyclerView, а затем настраивал разные представления для разных типов представлений. Тем самым устраняя ScrollView.

person Moonbloom    schedule 24.03.2018
comment
К сожалению, у меня есть случай, когда я не могу избавиться от ScrollView :( - person Pablo; 24.03.2018

Я смог решить эту проблему, заключив RecyclerView в НЕСКОЛЬКО дополнительных макетов. В моем случае причиной NestedScrollView является поддержка AppbarLayout и поведения вложенной прокрутки. Я загружаю фрагмент в NestedScrollView, который обычно содержит recyclerview.

Ключевым моментом здесь является ConstraintLayout в сочетании с FrameLayout.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/parent_nested_scroll"
    android:fillViewport="true"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <LinearLayout
        android:id="@+id/fragmentHolder"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <android.support.constraint.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            >

            <FrameLayout
                android:layout_width="0dp"
                android:layout_height="0dp"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toEndOf="parent">

                <android.support.v7.widget.RecyclerView
                    android:id="@+id/recyclerView"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"/>

            </FrameLayout>

        </android.support.constraint.ConstraintLayout>

    </LinearLayout>

</android.support.v4.widget.NestedScrollView>
person Shooky    schedule 20.12.2018