【问题标题】:RecyclerView getChildCount() and getItemCount() returns same valueRecyclerView getChildCount() 和 getItemCount() 返回相同的值
【发布时间】:2016-07-13 21:32:23
【问题描述】:

RecyclerView 有一个 InfiniteScrollListener 并且在该侦听器内部,在OnScrolled() 方法中,我计算可见项和总项数以检查是否应加载新项。当 totalItemCount 和 visibleItemCount 相同时,会导致加载无限循环。听众与我的其他 RecyclerViews 完美地工作,它没有 CoordinatorLayoutNestedScrollView 作为父母。 我想保留这种结构,因为客户不会接受更改。

我在一个 Activity 中有一个片段,它的布局是这样的

CoordinatorLayout{
 NestedScrollView{
    RecyclerView{
    }
 }
}

sdk 版本

compileSdkVersion 24
buildToolsVersion "23.0.3"
...
minSdkVersion 21
targetSdkVersion 24

fragment_profile.xml 作为父布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay"
        app:layout_behavior="com.paxotic.paxira.util.behavior.AppBarFlingBehavior">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="@dimen/app_bar_height_small"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="#000000"
                app:layout_collapseMode="parallax">

                <ImageView
                    android:id="@+id/img_background"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:alpha="0.5"
                    android:scaleType="centerCrop"
                    tools:src="@drawable/bg_greeting_activity" />

            </RelativeLayout>

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <include
        layout="@layout/activity_profile_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <android.support.design.widget.FloatingActionButton
       ... />

</android.support.design.widget.CoordinatorLayout>

fragment_profile.xml 作为子布局

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    ...

    <android.support.v7.widget.RecyclerView
        android:id="@+id/feedRecycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        android:paddingBottom="@dimen/spacing_normal"
        tools:listitem="@layout/list_item_activity" />

    ...

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

ProfileFragment.java:相关函数

private void init() {

    feedAdapter = new FeedAdapter(host);
    feedAdapter.setHasStableIds(true);

    LinearLayoutManager layoutManager = new LinearLayoutManager(host);
    feedRecycler.setLayoutManager(layoutManager);
    feedRecycler.setNestedScrollingEnabled(false);
    feedRecycler.setHasFixedSize(true);
    feedRecycler.setAdapter(feedAdapter);

    infiniteScrollListener = new InfiniteScrollListener(host, layoutManager) {
        @Override
        public void onLoadMore(int pageIndex) {
            if (!feedAdapter.isLoading) {
                loadFeed(pageIndex);
            }
        }
    };
    feedRecycler.addOnScrollListener(infiniteScrollListener);
}

InfiniteScrollListener.java

public abstract class InfiniteScrollListener extends RecyclerView.OnScrollListener {
    private int previousTotal = 0; // The total number of items in the dataset after the last load
    private boolean loading = false; // True if we are still waiting for the last set of data to load.
    private static final int VISIBLE_THRESHOLD = 5; // The minimum amount of items to have below your current scroll position before loading more.
    int firstVisibleItem, visibleItemCount, totalItemCount;

    private int current_page = 0;
    private int loadingItemCount;

    private LinearLayoutManager mLinearLayoutManager;

    public InfiniteScrollListener(Context context, LinearLayoutManager linearLayoutManager) {
        this.mLinearLayoutManager = linearLayoutManager;
        loadingItemCount = context.getResources().getInteger(R.integer.feed_pull_item_count);
    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);

        if (dy < 0) return;        // check for scroll down

        visibleItemCount = mLinearLayoutManager.getChildCount();
        totalItemCount = mLinearLayoutManager.getItemCount();
        firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();

        synchronized (this) {

            if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + VISIBLE_THRESHOLD)) {
                // End has been reached, Do something
                current_page++;
                onLoadMore(current_page);
                loading = true;
            }
        }
    }

    public abstract void onLoadMore(int current_page);

    public void setLoading(boolean loading) {
        this.loading = loading;
    }

    @Override
    public void onScrollStateChanged(RecyclerView view, int scrollState) {
        // Don't take any action on changed
    }
}

【问题讨论】:

  • 嘿,你找到解决方案了吗?我有同样的问题..
  • 我找到了核心问题,不幸的是@DarkLeonhart没有解决方案。问题是 NestedScrollView 的行为是因为它在屏幕上可见,所以它会绘制所有子项,并且 RecyclerView 返回所有可见的子项,这些子项是它的适配器拥有的所有项目,因此,getChildCount() 和 getItemCount() 为我们提供了相同的值。我现在已经改变了我的用户界面。我只用 RecyclerView 加载了 10 个项目,并且有一个按钮可以通向另一个无限滚动的活动。
  • @DarkLeonhart 你找到解决方案了吗?
  • as @dgngulcan 问题是当 RecyclreView 位于 NestedScrollView 内时,因此 RecyclerView 的滚动侦听器似乎没有任何影响。相反,我使用了基于stackoverflow.com/a/38570106/2178568 的 NestedScrollView 的滚动监听器

标签: java android infinite-scroll


【解决方案1】:

您从 getChildCount() getItemCount() 获得相同的值,因为 recyclerview 将返回项目/子项的总数。

您必须根据您的使用情况重写其中一种方法,以获得您想要的值。 在您的自定义 recyclerview 适配器中执行此操作。

为此,请将其添加到您的 recyclerview 适配器:

@Overide
public int getChildCount() {
//return your desired value here after obtaining it
}

【讨论】:

    【解决方案2】:

    您可以获得实际的观看次数。如果适配器有 15 个项目并且 ((LinearLayoutManager) myRecyclerView.getLayoutManager()).getChildCount() 返回 7,则在您更新新项目后,由于最大高度或静态高度值,视图中有两个项目可见,直到保持相同的高度。

    模型(适配器)中的项目数和视图数不是一回事。

    RecyclerView doesn't hold views for all 15 items in memory, it only has 7 in your case. When you scroll, it reuses those 7 views for displaying different items. The purpose of this is improving the rendering performance.

    如果你想得到 15,那么你应该使用 mAdapter.getItemCount() 来代替。

    【讨论】:

      【解决方案3】:

      您不应该在nestedScrollview 中使用recyclerView 垂直。 查找要在 RecyclerView 上显示的项目并开始获取新项目 你可以使用你的适配器。在RecyclerView.Adapter&lt;&gt; 中,您可以覆盖onViewAttachedToWindow()

      @Override
      public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) {
          super.onViewAttachedToWindow(holder);
          if ((getItemCount() - 1) == holder.getAdapterPosition()){
              Log.d(TAG,"list done");
              onLoadMore(current_page);
          } else {
              Log.d(TAG,"remain item : " + (getItemCount() - holder.getAdapterPosition() - 1));
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-20
        • 2021-05-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多