多视图嵌套RecyclerView滑动卡顿问题

7

我有一个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>

更新

以下是使用Fresco加载图片的代码:

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

1
测试用例尝试使用ViewCompat.setNestedScrollingEnabled(childRecyclerView, false); - AskNilesh
1
@NileshRathod 我尝试了,但是没有起作用。 - Masoud Mokhtari
1
可能是因为这个原因,如果不需要的话,请尝试删除这一行代码:mRvPromotions.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH); - Jeel Vankhede
1
@JeelVankhede 谢谢Jeel。但是这对我没有用。 - Masoud Mokhtari
1
好的,问题可能出在使用Fresco加载图像时的bitmap内存上,你能否发布加载image的代码? - Jeel Vankhede
显示剩余2条评论
2个回答

5

首先,您可以使用setInitialItemPrefetchCount()进行嵌套RecyclerView的预取功能。了解更多信息,请查看此文章

我认为,从服务器加载图片会阻塞主线程。您可以异步地进行此操作。也请查看这篇文章


0

由于同时存在滚动操作,出现这个问题是很自然的。为了解决这个问题,我建议通过将此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;
            }
        } ;

谢谢您的解决方案,但我也尝试了这个方法,问题还没有解决。 - Masoud Mokhtari
@MasoudMokhtari请将您的所有代码与XML一起发布,我已经做了很多次,它总是有效的。 - Mohammad Rbabah
@MasoudMokhtari 尝试禁用它,也许你错过了一个嵌套滚动视图。 - Mohammad Rbabah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接