Java 在创建之前,查找适合屏幕的RecyclerView项目数

Java 在创建之前,查找适合屏幕的RecyclerView项目数,java,android,android-recyclerview,Java,Android,Android Recyclerview,基本上,我试图通过编程找出一个RecyclerView中要容纳多少项(当然,用户也可以看到),以便确定要从缓存中提取多少项 我用的是LinearLayoutManager 另外,我知道LinearLayoutManager方法findLastVisibleItemPosition,但显然在这种情况下它是无用的,因为我们讨论的是初始化时间之前,而不是之后(因此返回-1) 我试着阅读文档或思考一个有创意但有效的想法,但我什么都没想到 有什么想法吗?这听起来很有趣,但只有当你的高度(垂直滚动)或宽度(

基本上,我试图通过编程找出一个RecyclerView中要容纳多少项(当然,用户也可以看到),以便确定要从缓存中提取多少项

我用的是LinearLayoutManager

另外,我知道LinearLayoutManager方法findLastVisibleItemPosition,但显然在这种情况下它是无用的,因为我们讨论的是初始化时间之前,而不是之后(因此返回-1)

我试着阅读文档或思考一个有创意但有效的想法,但我什么都没想到


有什么想法吗?

这听起来很有趣,但只有当你的高度(垂直滚动)或宽度(水平滚动)是固定的,这意味着没有包装内容时,这才有效

这里没有示例代码,也没有测试:

  • getCount
    创建一个带有setter的适配器,该setter在数据源为null/空时返回
  • getCount
    中,如果数据为空/空,则至少返回1
  • 确保
    onBindViewHolder()
    可以处理空/不存在的数据
  • onChildataTachStateChangeListener
    添加到您的RecyclerView中,每次调用侦听器时,使用
    视图
    视图.post(新建Runnable(){…增加适配器getCount…adapter.notifyItemInserted()}
    (该Runnable是避免崩溃+烧毁所必需的)
  • OnChildataTachStateChangeListener
    再次被调用>>比较
    getCount
    findLastVisibleItemPosition
    。如果
    getCount>findLastVisibleItemPosition+1
    删除该侦听器。适合ListView的固定大小视图数为
    findLastVisibleItemPosition+1
  • 获取数据并将其设置到适配器中,调用
    notifyDataSetChanged
  • 确保
    getCount
    从现在开始返回数据源长度
  • 您可以将listview隐藏在加载屏幕后面,也可以在
    onBindViewHolder

    编辑:

  • 创建一个适配器,当未设置任何数据时,该适配器将返回一个荒谬的高计数,并确保它在
    onBindViewHolder
  • 如果
    getItemCount()>getChildCount()
    getChildCount()是RecyclerView中可见的视图数,则在超级调用后扩展
    LinearLayoutManager
    并覆盖
    onLayoutChildren()
  • 主课

        public class MainActivity extends AppCompatActivity {
    
            private PreCountingAdapter mAdapter;
            private RecyclerView mRecyclerView;
            private PreCountLinearLayoutManager mPreCountLayoutManager;
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
                mPreCountLayoutManager = new PreCountLinearLayoutManager(this,
                        LinearLayoutManager.VERTICAL, false);
                mPreCountLayoutManager.setListener(new PreCountLinearLayoutManager.OnPreCountedListener() {
                    @Override
                    public void onPreCounted(int count) {
                        mPreCountLayoutManager.setListener(null);
                        loadData(count);
                    }
                });
                mRecyclerView.setLayoutManager(mPreCountLayoutManager);
                mAdapter = new PreCountingAdapter();
                mRecyclerView.setAdapter(mAdapter);
            }
    
            private void loadData(final int visibleItemCount) {
                // load data here, probably asynchronously,
                // for simplicity just an String Array with size visibleItemCount
                final List<String> data = new ArrayList<>();
                for (int i = 0; i < visibleItemCount; i++) {
                    data.add(String.format("child number #%d", i));
                }
                mRecyclerView.post(new Runnable() {
                    @Override
                    public void run() {
                        mAdapter.swapData(data);
                    }
                });
            }
    
            @Override
            protected void onDestroy() {
                mPreCountLayoutManager.setListener(null);
                super.onDestroy();
            }
        }
    
    预计算适配器类

        public class PreCountingAdapter extends RecyclerView.Adapter<PreCountingAdapter.ViewHolder> {
    
            private List<String> mData;
    
            public void swapData(List<String> data) {
                mData = data;
                notifyDataSetChanged();
            }
    
            public class ViewHolder extends RecyclerView.ViewHolder {
    
                View mItemView;
                TextView mTextView;
    
                public ViewHolder(View itemView) {
                    super(itemView);
                    mTextView = (TextView) itemView.findViewById(R.id.text_view);
                    mItemView = itemView;
                }
            }
    
            @Override
            public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                LayoutInflater inflater = LayoutInflater.from(parent.getContext());
                return new ViewHolder(inflater.inflate(R.layout.recycler_child, parent, false));
            }
    
            @Override
            public void onBindViewHolder(ViewHolder holder, int position) {
                if (mData == null) {
                    // we are in precounting stage
                    holder.mItemView.setVisibility(View.INVISIBLE);
                } else {
                    String item = mData.get(position);
                    holder.mItemView.setVisibility(View.VISIBLE);
                    holder.mTextView.setText(item);
                }
            }
    
            @Override
            public int getItemCount() {
                return mData == null ? Integer.MAX_VALUE : mData.size();
            }
    
        }
    
    公共类预计算适配器扩展了RecyclerView.Adapter{
    私有列表数据;
    公共无效交换数据(列表数据){
    mData=数据;
    notifyDataSetChanged();
    }
    公共类ViewHolder扩展了RecyclerView.ViewHolder{
    视图;
    文本视图mTextView;
    公共视图持有者(视图项视图){
    超级(项目视图);
    mTextView=(TextView)itemView.findViewById(R.id.text\u视图);
    mItemView=项目视图;
    }
    }
    @凌驾
    public ViewHolder onCreateViewHolder(视图组父级,int-viewType){
    LayoutInflater充气器=LayoutInflater.from(parent.getContext());
    返回新的视图保持架(充气器。充气(R.layout.recycler_child,parent,false));
    }
    @凌驾
    公共无效onBindViewHolder(ViewHolder,int位置){
    if(mData==null){
    //我们正处于预计算阶段
    holder.mItemView.setVisibility(视图不可见);
    }否则{
    字符串项=mData.get(位置);
    holder.mItemView.setVisibility(View.VISIBLE);
    holder.mTextView.setText(项目);
    }
    }
    @凌驾
    public int getItemCount(){
    返回mData==null?Integer.MAX_值:mData.size();
    }
    }
    
    我测试了它,因为最后一个视图从未连接,所以它无法工作。(Doh,在编写时我应该很清楚)添加了另一个解决方案,简单地测试了它,到目前为止它还可以工作。什么是修复?它从来没有修复过,它总是覆盖几乎所有可用空间(匹配父项),就像Android中的大多数视图一样。另外,你能更好地解释一下为什么你的解决方案会起作用吗?另外,我认为一个更简单的方法是实时计算recycler视图的高度,并根据每个项目的高度进行划分(然后需要通过编程或从维度xml进行设置,以便在创建项本身之前可以使用它…)对于Fixed,我的意思是每个子视图都必须有一个固定的高度,独立于要显示的数据。例如,textview总是有两行文本,RecyclerView本身可以是match_parent,这不是问题。虽然您可以计算每个项目的高度并简单地计算出数量,但当您开始计算marg时,它很快就会变得复杂另一方面,我的解决方案只是简单地欺骗LinearLayoutManager,让它完全完成它通常所做的工作:布局子视图,直到填充RecyclerView。此外,几乎没有开销,因为当真正的数据进入时,子视图会被回收和重用。您仍然可以更改字体大小,行数字等,它仍然会工作。
        public class PreCountingAdapter extends RecyclerView.Adapter<PreCountingAdapter.ViewHolder> {
    
            private List<String> mData;
    
            public void swapData(List<String> data) {
                mData = data;
                notifyDataSetChanged();
            }
    
            public class ViewHolder extends RecyclerView.ViewHolder {
    
                View mItemView;
                TextView mTextView;
    
                public ViewHolder(View itemView) {
                    super(itemView);
                    mTextView = (TextView) itemView.findViewById(R.id.text_view);
                    mItemView = itemView;
                }
            }
    
            @Override
            public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                LayoutInflater inflater = LayoutInflater.from(parent.getContext());
                return new ViewHolder(inflater.inflate(R.layout.recycler_child, parent, false));
            }
    
            @Override
            public void onBindViewHolder(ViewHolder holder, int position) {
                if (mData == null) {
                    // we are in precounting stage
                    holder.mItemView.setVisibility(View.INVISIBLE);
                } else {
                    String item = mData.get(position);
                    holder.mItemView.setVisibility(View.VISIBLE);
                    holder.mTextView.setText(item);
                }
            }
    
            @Override
            public int getItemCount() {
                return mData == null ? Integer.MAX_VALUE : mData.size();
            }
    
        }