【问题标题】:Nested RecyclerView with Multiple View Lagging Scroll具有多视图滞后滚动的嵌套 RecyclerView
【发布时间】:2019-02-09 07:23:08
【问题描述】:

我有一个带有多个视图的 recyclerView,其中每一行都是一个 recyclerView。当我滚动 recyclerView 时,创建的每一行都是滞后的。这是我的一些代码。在下面你可以看到主recyclerView的配置:

LinearLayoutManager mLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
    mRvPromotions.setLayoutManager(mLayoutManager);
    mRvPromotions.setItemViewCacheSize(20);
    mRvPromotions.setDrawingCacheEnabled(true);
    mRvPromotions.setHasFixedSize(true);
    mRvPromotions.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
    mRvPromotions.setAdapter(adapter);

您可以在下面看到绑定在适配器中的内部 recyclerView 代码:

mRvPromotion.setLayoutManager(new GridLayoutManager(itemView.getContext(), 3));
    mRvPromotion.setItemViewCacheSize(20);
    mRvPromotion.setDrawingCacheEnabled(true);
    mRvPromotion.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
    adapter = new PlaylistPromotionsRVAdapter(new PlaylistModelCallBack(), new PlaylistPromotionVHFactory());
    mRvPromotion.setAdapter(adapter);
    adapter.submitList(getVM().getPlaylist());

我使用mRvPromotion.setNestedScrollingEnabled(false);ViewCompat.setNestedScrollingEnabled(childRecyclerView, false);,但存在滞后行为钢。 对于加载图像,我使用了 Fresco 并调整了它的大小配置。 如何防止滚动滞后?

编辑

这是我的适配器:

public class PlaylistRVAdapter extends ListAdapter<PlayListPromotionAndSlider, BaseViewHolder> {

private final PlaylistPageVHFactory mFactory;
private final PublishSubject<PlaylistSliderVHAction> mClickSliderPS = PublishSubject.create();
private final PublishSubject<PlaylistPromotionsVHAction> mClickPromotionPS = PublishSubject.create();

@Inject
PlaylistRVAdapter(@NonNull PlaylistPromotionModelCallBack diffCallback, PlaylistPageVHFactory factory) {
    super(diffCallback);
    mFactory = factory;
}

@NonNull
@Override
public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    return mFactory.create(parent, viewType);
}

@Override
public void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {
    switch (getItemViewType(position)) {
        case 0:
            PlaylistSliderVH sliderVH = (PlaylistSliderVH) holder;
            sliderVH.getVM().setObject(getItem(position).getSlide());
            sliderVH.bind();
            sliderVH.itemOnClick(mClickSliderPS);
            break;
        case 1:
            PlaylistPromotionsVH promotionsVH = (PlaylistPromotionsVH) holder;
            promotionsVH.getVM().setObject(getItem(position).getPromotion());
            promotionsVH.bind();
            promotionsVH.itemOnClick(mClickPromotionPS);
            break;
    }
}

public Observable<PlaylistSliderVHAction> getClickPS() {
    return mClickSliderPS;
}

public PublishSubject<PlaylistPromotionsVHAction> getmClickPromotionPS() {
    return mClickPromotionPS;
}

@Override
public int getItemViewType(int position) {
    return getItem(position).getSlide() != null ? 0 : 1;
}

}

例如,我的 viewHolder PlaylistPromotionsVH 如下所示:

public class PlaylistPromotionsVH extends BaseViewHolder<PlaylistPromotionsVHAction, PlaylistMasterModel, PlaylistPromotionsVM> {

@BindView(R.id.txtPromotionTitle)
AppCompatTextView mTxtPromotionTitle;
@BindView(R.id.txtMore)
AppCompatTextView mTxtMore;
@BindView(R.id.rvPromotion)
RecyclerView mRvPromotion;

PlaylistPromotionsRVAdapter adapter;

public PlaylistPromotionsVH(View itemView, PlaylistPromotionsVM viewModel) {
    super(itemView, viewModel);
    ButterKnife.bind(this, itemView);
}

@Override
public void bind() {
    mTxtPromotionTitle.setText(mVM.getPlaylistName());
    mRvPromotion.setLayoutManager(new GridLayoutManager(itemView.getContext(), 3));
    mRvPromotion.setItemViewCacheSize(20);
    mRvPromotion.setDrawingCacheEnabled(true);
    mRvPromotion.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
    mRvPromotion.setHasFixedSize(true);
    int spacing = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12,
            itemView.getContext().getResources().getDisplayMetrics());
    mRvPromotion.addItemDecoration(new RecyclerView.ItemDecoration() {
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            int position = parent.getChildAdapterPosition(view); // item position
            int spanCount = 3;
            if (position >= 0) {
                int column = position % spanCount; // item column

                outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
                outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)

                if (position < spanCount) { // top edge
                    outRect.top = spacing;
                }
                outRect.bottom = spacing; // item bottom
            } else {
                outRect.left = 0;
                outRect.right = 0;
                outRect.top = 0;
                outRect.bottom = 0;
            }
        }
    });

    adapter = new PlaylistPromotionsRVAdapter(new PlaylistModelCallBack(), new PlaylistPromotionVHFactory());
    mRvPromotion.setAdapter(adapter);

    adapter.submitList(getVM().getPlaylist());
}

@Override
public void itemOnClick(PublishSubject<PlaylistPromotionsVHAction> actionSubject) {
    RxView.clicks(mTxtMore)
            .map(o -> new PlaylistPromotionsVHAction(getAdapterPosition()))
            .repeat()
            .subscribe(actionSubject);
}

}

在下面你可以看到主recyclerView每一行的布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:background="@color/colorPromotionBackground"
android:descendantFocusability="blocksDescendants"
app:layout_behavior="@string/appbar_scrolling_view_behavior">

<RelativeLayout
    android:id="@+id/rlPromotionTitle"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.AppCompatTextView
        android:id="@+id/txtPromotionTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="16dp"
        android:layout_toRightOf="@+id/txtMore"
        android:gravity="right"
        android:textColor="@android:color/white"
        tools:ignore="RtlHardcoded" />

    <android.support.v7.widget.AppCompatTextView
        android:id="@+id/txtMore"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_centerVertical="true"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:background="@drawable/ic_see_more" />
</RelativeLayout>
<android.support.v7.widget.RecyclerView
    android:id="@+id/rvPromotion"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/rlPromotionTitle"
    android:focusableInTouchMode="true"
    android:overScrollMode="never"
    android:scrollbars="none"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</RelativeLayout>

更新

这是我用壁画加载图像的代码:

ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
            .setResizeOptions(new ResizeOptions(width, height))
            .build();
    simpleDraweeView.setController(
            Fresco.newDraweeControllerBuilder()
                    .setOldController(simpleDraweeView.getController())
                    .setImageRequest(request)
                    .build());

【问题讨论】:

  • 测试用例尝试ViewCompat.setNestedScrollingEnabled(childRecyclerView, false);
  • @NileshRathod 我试过了,但没用。
  • 可能是这个原因,如果不需要,请尝试删除此行:mRvPromotions.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
  • @JeelVankhede 谢谢Jeel。但这对我不起作用。
  • 好吧,问题可能出在bitmap 使用Fresco 加载图像的内存上,你能发布加载代码image 吗?

标签: android android-recyclerview fresco nestedrecyclerview


【解决方案1】:

首先,您可以使用setInitialItemPrefetchCount() 为嵌套的 RecyclerView 提供预取功能。欲了解更多信息,请查看article

我认为,主要原因是从服务器加载图像阻塞了主线程。您可以异步执行此操作。请检查这个article

【讨论】:

    【解决方案2】:

    这个问题很自然,因为同时有滚动操作,为了解决这个问题,我建议禁用所有孩子的滚动操作,只需将此 LayoutManger 添加到每个孩子

    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false){
                @Override
                public boolean canScrollVertically() {
                    return false;
                }
            };
    

    如果孩子持有网格布局管理器这样禁用它

     new GridLayoutManager(getContext(),2){
                @Override
                public boolean canScrollVertically() {
                    return false;
                }
            } ;
    

    【讨论】:

    • 感谢您的解决方案,但我也尝试过,但问题尚未解决。
    • @MasoudMokhtari 请用 XML 发布你的所有代码我做了很多次,它总是有效
    • @MasoudMokhtari 尝试全部禁用它,因为你错过了一个嵌套滚动视图
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 2018-01-30
    • 1970-01-01
    • 2016-09-15
    • 2019-09-18
    • 2014-10-08
    相关资源
    最近更新 更多