RecyclerView setHasFixedSize 이해 데 문제가 setHasFixedSize()있습니다.

이해하는 데 문제가 setHasFixedSize()있습니다. RecyclerView문서에서 크기 가 변경되지 않을 때 최적화에 사용된다는 것을 알고 있습니다.

그래도 무슨 뜻입니까? 대부분의 경우 ListView거의 항상 크기가 고정되어 있습니다. 어떤 경우에는 고정 크기가 아닐까요? 화면에서 차지하는 실제 부동산이 콘텐츠와 함께 증가한다는 의미입니까?



답변

RecyclerView 의 매우 단순화 된 버전은 다음과 같습니다.

void onItemsInsertedOrRemoved() {
   if (hasFixedSize) layoutChildren();
   else requestLayout();
}

이 링크 는 통화 requestLayout비용이 비싼 이유를 설명 합니다. 기본적으로 항목을 삽입, 이동 또는 제거 할 때마다 RecyclerView의 크기 (너비 및 높이)가 변경 될 수 있으며,보기 계층 구조의 다른보기의 크기가 변경 될 수 있습니다. 항목을 자주 추가하거나 제거하는 경우 특히 문제가됩니다.

setHasFixedSize어댑터의 내용을 변경해도 높이나 너비가 변경되지 않는 경우 true 로 설정 하여 불필요한 레이아웃 패스를 피하십시오 .


업데이트 : JavaDoc이 메소드의 실제 기능을 더 잘 설명하도록 업데이트되었습니다.

RecyclerView의 크기가 어댑터 내용의 영향을받지 않는다는 것을 미리 알 수있는 경우 RecyclerView는 여러 가지 최적화를 수행 할 수 있습니다. RecyclerView는 여전히 다른 요소 (예 : 부모의 크기)에 따라 크기를 변경할 수 있지만이 크기 계산은 자식의 크기 나 어댑터의 내용 (어댑터의 항목 수 제외)에 따라 달라질 수 없습니다.

RecyclerView를 사용하는 경우이 범주에 해당하면 {@code true}로 설정하십시오. 어댑터 내용이 변경 될 때 RecyclerView가 전체 레이아웃을 무효화하지 않도록 할 수 있습니다.

@param hasFixedSize 어댑터 변경이 RecyclerView의 크기에 영향을 줄 수없는 경우 true입니다.


답변

setHasFixedSize각 항목의 크기가 아니라 RecyclerView 자체와 관련이 있는지 확인할 수 있습니다.

이제 android:layout_height="wrap_content"RecyclerView를 사용할 수 있습니다 . 그 중에서도 RecyclerView가 비어 있으면 CollapsingToolbarLayout이 축소되지 않아야 함을 알 수 있습니다. setHasFixedSize(false)RecylcerView에서 사용할 때만 작동합니다 .

setHasFixedSize(true)RecyclerView에서 사용 하는 경우 RecyclerView가 실제로 비어 있어도 CollapsingToolbarLayout이 축소되는 것을 방지하는이 동작은 작동하지 않습니다.

경우 setHasFixedSize항목의 크기와 관련 된 RecyclerView 더 항목이 없을 때, 그것은 영향을주지해야한다.


답변

ListView에는 비슷한 목록 함수가 있었는데 개별 목록 항목 높이의 크기에 대한 정보를 반영했다고 생각합니다. RecyclerView에 대한 설명서는 항목의 크기가 아니라 RecyclerView 자체의 크기를 나타냅니다.

setHasFixedSize () 메소드 위의 RecyclerView 소스 주석에서 :

 * RecyclerView can perform several optimizations if it can know in advance that changes in
 * adapter content cannot change the size of the RecyclerView itself.
 * If your use of RecyclerView falls into this category, set this to true.


답변

원 총리는 우리는 설정 setHasFixedSize(true)에서 RecyclerView의 재활용 크기가 고정되어 어댑터의 내용에 의해 영향을받지 않는 것을 의미한다. 그리고이 경우 onLayout어댑터의 데이터를 업데이트 할 때 리사이클 러에서 호출되지 않습니다 (그러나 예외가 있습니다).

예를 보자.

RecyclerViewRecyclerViewDataObserver( 이 파일 찾기 기본 implemntation 여러 가지 방법으로)을 주요 중요하다 :

void triggerUpdateProcessor() {
    if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
        ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
    } else {
        mAdapterUpdateDuringMeasure = true;
        requestLayout();
    }
}

이 메소드는 setHasFixedSize(true)다음을 통해 어댑터의 데이터를 설정 하고 업데이트하면 호출됩니다 notifyItemRangeChanged, notifyItemRangeInserted, notifyItemRangeRemoved or notifyItemRangeMoved. 이 경우 리사이클 러 onLayoutrequestLayout대한 호출은 없지만 자식 업데이트 에 대한 호출이 있습니다.

우리가 설정하지만 setHasFixedSize(true)통해 어댑터의 데이터를 업데이트합니다 notifyItemChanged다음에 호출이 onChange리사이클의 기본의 RecyclerViewDataObserver및없이 호출 triggerUpdateProcessor. 이 경우 재활용은 onLayout우리가 설정 될 때마다 호출 setHasFixedSize true또는 false.

// no calls to triggerUpdateProcessor
@Override
public void onChanged() {
    assertNotInLayoutOrScroll(null);
     mState.mStructureChanged = true;

     processDataSetCompletelyChanged(true);
     if (!mAdapterHelper.hasPendingUpdates()) {
         requestLayout();
     }
}

// calls to triggerUpdateProcessor
@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
    assertNotInLayoutOrScroll(null);
    if (mAdapterHelper.onItemRangeChanged(positionStart, itemCount, payload)) {
        triggerUpdateProcessor();
    }
}

직접 확인하는 방법 :

사용자 정의 작성 RecyclerView및 대체 :

override fun requestLayout() {
    Log.d("CustomRecycler", "requestLayout is called")
    super.requestLayout()
}

override fun invalidate() {
    Log.d("CustomRecycler", "invalidate is called")
    super.invalidate()
}

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
    Log.d("CustomRecycler", "onLayout is called")
    super.onLayout(changed, l, t, r, b)
}

리사이클 러 크기를 match_parent(xml) 로 설정하십시오 . 어댑터의 데이터를 사용하여 업데이트하는 것을 시도 replaceData하고 replaceOne 최저치를 함께 setHasFixedSize(true)다음과 false.

// onLayout is called every time
fun replaceAll(data: List<String>) {
    dataSet.clear()
    dataSet.addAll(data)
    this.notifyDataSetChanged()
}

// onLayout is called only for setHasFixedSize(false)
fun replaceOne(data: List<String>) {
    dataSet.removeAt(0)
    dataSet.addAll(0, data[0])
    this.notifyItemChanged(0)
}

그리고 당신의 로그를 확인하십시오.

내 로그 :

// for replaceAll
D/CustomRecycler: requestLayout is called
D/CustomRecycler: onMeasure is called
D/CustomRecycler: onMeasure is called
D/CustomRecycler: onLayout
D/CustomRecycler: requestLayout is called
D/CustomRecycler: requestLayout is called
D/CustomRecycler: onDraw is called

// for replaceOne
D/CustomRecycler: requestLayout is called
D/CustomRecycler: onDraw is called
D/CustomRecycler: requestLayout is called
D/CustomRecycler: onDraw is called

요약하다:

setHasFixedSize(true)호출 이외의 다른 방법으로 관찰자에게 알리면서 어댑터의 데이터를 설정 하고 업데이트 notifyDataSetChanged하면 recycler onLayout메소드에 대한 호출이 없기 때문에 성능이 있습니다 .


답변

우리가있는 경우 RecyclerViewmatch_parent같은 높이 / 폭 , 우리는 추가해야합니다 setHasFixedSize(true)의 크기 때문에 RecyclerView삽입하거나 그것으로 항목을 삭제 변경되지 않습니다 자체.

setHasFixedSize은 우리가 함께 RecyclerView이 경우는 false해야 wrap_content같은 높이 / 폭 어댑터에 의해 삽입 된 각 요소의 크기를 변경할 수 있기 때문에 Recycler삽입 된 항목에 따라 / 삭제를, 그래서의 크기 Recycler우리가 추가 다를 수 있습니다 때마다 / 삭제 품목.

더 명확하게 사용하면

<android.support.v7.widget.RecyclerView
    android:id="@+id/my_recycler_view"
    android:scrollbars="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

사용할 수있다 my_recycler_view.setHasFixedSize(true)

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

우리는 사용한다 my_recycler_view.setHasFixedSize(false)우리는 또한 사용하는 경우이 적용 wrap_content폭으로


답변

setHasFixedSize (true)는 RecyclerView에 너비와 높이가 고정 된 자식 (항목)이 있음을 의미합니다. 이렇게하면 어댑터를 기반으로 전체 목록의 정확한 높이와 너비를 알아 냄으로써 RecyclerView가 더 잘 최적화됩니다.


답변

이 경우 recyclerview의 애니메이션에 영향을 미칩니다 false. 삽입 및 제거 애니메이션은 표시되지 않습니다. truerecyclerview에 애니메이션을 추가 한 경우에 대비 하십시오 .