Android 如何强制RecyclerView.Adapter在所有元素上调用onBindViewHolder()

Android 如何强制RecyclerView.Adapter在所有元素上调用onBindViewHolder(),android,textview,android-recyclerview,Android,Textview,Android Recyclerview,我有一个VerticalGridView,它使用RecyclerView.Adapter来填充元素。我发现,如果潜在元素不在视口中,则不会调用onBindViewHolder()方法。不幸的是,这会导致来自不同方法的NullPointerException,因为我正在onBindViewHolder()方法中捕获TextView引用,并将其传递给外部变量以供以后操作 @Override public void onBindViewHolder(RecyclerView.ViewHolder ho

我有一个
VerticalGridView
,它使用
RecyclerView.Adapter
来填充元素。我发现,如果潜在元素不在视口中,则不会调用
onBindViewHolder()
方法。不幸的是,这会导致来自不同方法的
NullPointerException
,因为我正在
onBindViewHolder()
方法中捕获
TextView
引用,并将其传递给外部变量以供以后操作

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    final ViewHolder viewHolder = (ViewHolder) holder;
    viewHolder.txtCategoryName.setText(categories.get(position).getStrCategory());
    categories.get(position).setTxtViewReference(viewHolder.txtCategoryDefectTotal);
    viewHolder.categoryBoxRoot.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            for(CategoryListItem catItem : categories){
                if(catItem.getStrCategory().equals(viewHolder.txtCategoryName.getText())){
                    int index = Defects.getInstance().getCategories().indexOf(catItem) + 1;
                    MainInterface.grids.get(index).bringToFront();
                    MainInterface.grids.get(index).setVisibility(View.VISIBLE);
                    for(VerticalGridView grid : MainInterface.grids){
                        int gridIndex = MainInterface.grids.indexOf(grid);
                        if(gridIndex != index){
                            grid.setVisibility(View.INVISIBLE);
                        }
                    }
                    break;
                }
            }

        }
    });
据我所知,对
TextView
的引用是在实例化
Viewholder
对象时创建的

public class ViewHolder extends RecyclerView.ViewHolder {

    public TextView txtCategoryName;
    public TextView txtCategoryDefectTotal;
    public View categoryBoxRoot;

    public ViewHolder(View itemView) {
        super(itemView);
        txtCategoryName = (TextView) itemView.findViewById(R.id.textViewCategoryName);
        txtCategoryDefectTotal = (TextView) itemView.findViewById(R.id.textViewCategoryTotalDefects);
        categoryBoxRoot = itemView.findViewById(R.id.root_category_box);
    }
}
适配器
实例化时,是否有方法强制对所有元素至少调用一次
onBindViewHolder()

我试图提出这些建议,但没有成功

我理解在所有元素上强制执行
onBindViewHolder()
,会违反规则。因此,我愿意接受关于如何捕捉
TextView
参考的任何其他建议

作为这个问题的临时解决方案,我能够在生成
NullPointerException
的方法周围使用try-catch块。然而,我担心缺乏参考意味着我将来可能会引入错误。

了解流程

public class ThemeGridAdapter extends RecyclerView.Adapter<ThemeGridAdapter.ViewHolder> {
    private OnItemClickedListener listener;
    private List<Theme> mDataset;

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView title;
        public TextView subtitle;
        //        public SimpleDraweeView image;
        public ImageView img;
        public ViewGroup container;

        public ViewHolder(RelativeLayout v) {
            super(v);
            container = v;
            title = (TextView) v.findViewById(R.id.theme_name_text);
            subtitle = (TextView) v.findViewById(R.id.theme_name_type);
//            image = (SimpleDraweeView) v.findViewById(R.id.cell_img);
            img = (ImageView) v.findViewById(R.id.cell_img);
        }
    }

    public ThemeGridAdapter(List<Theme> dataset) {
        mDataset = dataset;
    }

    @Override
    public ThemeGridAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                          int viewType) {
        RelativeLayout v = (RelativeLayout) LayoutInflater.from(parent.getContext())
                .inflate(R.layout.cell, parent, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        holder.title.setText(mDataset.get(position).getTitle());
        holder.subtitle.setText(mDataset.get(position).getAuthor());
//        Uri uri = Uri.parse(mDataset.get(position).getUrl());
        holder.img.setImageResource(mDataset.get(position).getImage());
//        holder.image.setImageURI(uri);
        holder.container.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (listener != null)
                    listener.onItemClicked(holder.getAdapterPosition());
            }
        });

    }

    @Override
    public int getItemCount() {
        return mDataset.size();
    }

    public void setListener(OnItemClickedListener listener) {
        this.listener = listener;
    }
}
public类ThemeGridAdapter扩展了RecyclerView.Adapter{
私人监听;
私有列表数据集;
公共静态类ViewHolder扩展了RecyclerView.ViewHolder{
公共文本视图标题;
公共文本视图字幕;
//公众形象;
公共图像视图img;
公共视图组容器;
公共视图持有者(相对视图v){
超级(五);
容器=v;
title=(TextView)v.findViewById(R.id.theme\u name\u text);
subtitle=(TextView)v.findViewById(R.id.theme\u name\u type);
//image=(simpledraweview)v.findViewById(R.id.cell\u img);
img=(ImageView)v.findViewById(R.id.cell\u img);
}
}
公共主题集成适配器(列表数据集){
mDataset=数据集;
}
@凌驾
public ThemeGridAdapter.ViewHolder onCreateViewHolder(视图组父级、,
int视图类型){
RelativeLayout v=(RelativeLayout)LayoutFlater.from(parent.getContext())
.充气(R.layout.cell,父级,假);
返回新的视图持有者(v);
}
@凌驾
公共无效onBindViewHolder(最终视图持有人,最终整型位置){
holder.title.setText(mDataset.get(position.getTitle());
holder.subtitle.setText(mDataset.get(position.getAuthor());
//Uri=Uri.parse(mDataset.get(position.getUrl());
holder.img.setImageResource(mDataset.get(position.getImage());
//holder.image.setImageURI(uri);
holder.container.setOnClickListener(新视图.OnClickListener(){
@凌驾
公共void onClick(视图v){
if(侦听器!=null)
onItemClicked(holder.getAdapterPosition());
}
});
}
@凌驾
public int getItemCount(){
返回mDataset.size();
}
公共void setListener(OnItemClickedListener侦听器){
this.listener=listener;
}
}

检查绑定视图的样式

  public class CrimeListFragment extends Fragment {


    private static final String SAVED_SUBTITLE_VISIBLE = "subtitle";

    private static final int REQUEST_CRIME = 1;

    private RecyclerView mRecyclerView;
    private CrimeAdapter mCrimeAdapter;

    private boolean mSubtitleVisible;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_crime_list, container, false);

        mRecyclerView = (RecyclerView) view.findViewById(R.id.crime_recycler_view);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

        if (savedInstanceState != null){
            mSubtitleVisible = savedInstanceState.getBoolean(SAVED_SUBTITLE_VISIBLE);
        }
        updateUI();


        return view;
    }

    private void updateUI() {

        CrimeLab crimeLab = CrimeLab.get(getActivity());
        List<Crime> crimes = crimeLab.getCrimes();

        if (mCrimeAdapter == null) {
            mCrimeAdapter = new CrimeAdapter(crimes);
            mRecyclerView.setAdapter(mCrimeAdapter);
        } else {
            mCrimeAdapter.setCrimes(crimes);
            mCrimeAdapter.notifyDataSetChanged();
        }
        updateSubtitle();
    }

    private class CrimeHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        private TextView mTitleTextView;
        private TextView mDateTextView;
        private CheckBox mSolvedCheckBox;
        private Crime mCrime;


        public CrimeHolder(View itemView) {
            super(itemView);

            itemView.setOnClickListener(this);

            mTitleTextView = (TextView) itemView.findViewById(R.id.list_item_crime_title_text_view);
            mDateTextView = (TextView) itemView.findViewById(R.id.list_item_crime_date_text_view);
            mSolvedCheckBox = (CheckBox) itemView.findViewById(R.id.list_item_crime_solved_checkbox);

        }

        public void bindCrime(Crime crime) {

            mCrime = crime;

            mTitleTextView.setText(mCrime.getTitile());
            mDateTextView.setText(mCrime.getDate().toString());
            mSolvedCheckBox.setChecked(mCrime.isSolved());
        }

        @Override
        public void onClick(View v) {

            /*Toast.makeText(getActivity(),mCrime.getTitile() + "clicked!", Toast.LENGTH_SHORT).show();*/

            /*Intent for calling activity from fragment*/
           /* Intent intent = new Intent(getActivity(), CrimeActivity.class);*/
            /*Intent intent = CrimeActivity.newIntent(getActivity(),mCrime.getId());*/
            Intent intent = CrimePagerActivity.newIntent(getActivity(), mCrime.getId());
            /*startActivityForResult(intent,REQUEST_CRIME);*/
            startActivity(intent);
        }
    }

    private class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder> {

        private List<Crime> mCrimes;

        public CrimeAdapter(List<Crime> crimes) {

            mCrimes = crimes;
        }

        @Override
        public CrimeHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            LayoutInflater layoutInflater = LayoutInflater.from(getActivity());

            View view = layoutInflater.inflate(R.layout.list_item_crime, parent, false);
            return new CrimeHolder(view);

        }

        @Override
        public void onBindViewHolder(CrimeHolder holder, int position) {

            Crime crime = mCrimes.get(position);
            /*holder.mTextView.setText(crime.getTitile());*/
            holder.bindCrime(crime);

        }

        @Override
        public int getItemCount() {
            return mCrimes.size();
        }

        public void setCrimes(List<Crime> crimes) {

            mCrimes = crimes;
        }
    }


    @Override
    public void onResume() {
        super.onResume();
        updateUI();
    }


    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_CRIME) {

        }
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.fragment_crime_list, menu);

        MenuItem subtitleItem = menu.findItem(R.id.menu_item_show_subtitle);
        if (mSubtitleVisible){
            subtitleItem.setTitle(R.string.hide_subtitle);
        }else {
            subtitleItem.setTitle(R.string.show_subtitle);
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {

            case R.id.menu_item_new_crime:

                Crime crime = new Crime();
                CrimeLab.get(getActivity()).addCrime(crime);
                Intent intent = CrimePagerActivity.newIntent(getActivity(), crime.getId());
                startActivity(intent);
                return true;

            case R.id.menu_item_show_subtitle:

                mSubtitleVisible = !mSubtitleVisible;
                getActivity().invalidateOptionsMenu();
                updateSubtitle();
                return true;

            default:
                return super.onOptionsItemSelected(item);
        }
    }

    private void updateSubtitle(){

        CrimeLab crimeLab = CrimeLab.get(getActivity());
        int crimeCount = crimeLab.getCrimes().size();

        String subtitle = getString(R.string.subtitle_format,crimeCount);
        if (!mSubtitleVisible){

            subtitle  = null;
        }
        AppCompatActivity appCompatActivity = (AppCompatActivity)getActivity();
        appCompatActivity.getSupportActionBar().setSubtitle(subtitle);

    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean(SAVED_SUBTITLE_VISIBLE,mSubtitleVisible);
    }
}
公共类CrimeListFragment扩展了片段{
保存的私有静态最终字符串\u SUBTITLE\u VISIBLE=“SUBTITLE”;
私人静态最终int请求_犯罪=1;
私人回收视图mRecyclerView;
私家侦探mCrimeAdapter;
私有布尔msubtitlevible;
@凌驾
创建时的公共void(@Nullable Bundle savedInstanceState){
super.onCreate(savedInstanceState);
设置选项菜单(真);
}
@可空
@凌驾
创建视图时的公共视图(LayoutFlater充气机、@Nullable ViewGroup容器、@Nullable Bundle savedInstanceState){
视图=充气机。充气(R.layout.fragment\u crime\u list,container,false);
mRecyclerView=(RecyclerView)view.findViewById(R.id.crime\u recycler\u视图);
setLayoutManager(新的LinearLayoutManager(getActivity());
如果(savedInstanceState!=null){
msubtitlevible=savedInstanceState.getBoolean(保存的字幕可见);
}
updateUI();
返回视图;
}
私有void updateUI(){
CrimeLab CrimeLab=CrimeLab.get(getActivity());
列表犯罪=crimeLab.getCrimes();
if(mcrimedapter==null){
mCrimeAdapter=新的CrimeAdapter(犯罪);
mRecyclerView.setAdapter(mcrimedapter);
}否则{
mCrimeAdapter.setCrimes(罪行);
mcrimedapter.notifyDataSetChanged();
}
更新subtitle();
}
私有类CrimeHolder扩展了RecyclerView.ViewHolder实现了View.OnClickListener{
私有文本视图mTitleTextView;
私有文本视图mDateTextView;
私有复选框mSolvedCheckBox;
私人犯罪;
公共犯罪记录(查看项目视图){
超级(项目视图);
setOnClickListener(这个);
mTitleTextView=(TextView)itemView.findViewById(R.id.list\u item\u crime\u title\u text\u view);
mDateTextView=(TextView)itemView.findViewById(R.id.list\u item\u crime\u date\u text\u view);
mSolvedCheckBox=(复选框)itemviewbyd(R.id.list\u item\u crime\u solved\u CheckBox);
}
公共犯罪(刑事犯罪){
犯罪;
mTitleTextView.setText(mCrime.getTitile());
mDateTextView.setText(mcinite.getDate().toString());
mSolvedCheckBox.setChecked(mcinite.isSolved());
}
@凌驾
公共空间
@Override
public void onResume(){
    super.onResume();
    VerticalGridView defectGrid = grids.get(0);
    RecyclerView.Adapter adapter = defectGrid.getAdapter();
    defectGrid.smoothScrollToPosition(adapter.getItemCount()-1);
    defectGrid.smoothScrollToPosition(0);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    final ViewHolder viewHolder = (ViewHolder) holder;
    viewHolder.txtCategoryName.setText(categories.get(position).getStrCategory());
    viewHolder.txtCategoryDefectTotal.setText(String.valueOf(categories.get(position).getTotalDefectsInCategory()));
}
grids.get(0).getAdapter().notifyDataSetChanged();
RecyclerView.Adapter adapter = recList.getAdapter();
recList.setAdapter(null);
recList.setAdapter(adapter);
 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            mAdapter.notifyDataSetChanged();
        }
    });
<androidx.core.widget.NestedScrollView
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvGrid"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:nestedScrollingEnabled="false" />
</androidx.core.widget.NestedScrollView>