androidandroid-recyclerviewandroid-viewholder

onCreateViewHolder of RecyclerView.Adapter is called twice or more, multiple times


I'm currently developing an application which uses RecyclerView.

On reviewing LogCat I noticed that onCreateViewHolder was called twice after it was instantiated.

09-22 05:22:55.209 V/Adapter﹕ Construct
09-22 05:22:55.213 V/Adapter﹕ onCreateViewHolder
09-22 05:22:55.224 V/Adapter﹕ onBindViewHolder
09-22 05:22:55.240 V/Adapter﹕ onCreateViewHolder
09-22 05:22:55.247 V/Adapter﹕ onBindViewHolder

Also onBindViewHolder was called twice though I know it is called whenever the items are recycled.

But I think for onCreateViewHolder it is sufficient to be called once.

Is this abnormal behavior? If so, how can it be fixed?


Solution

  • It's not abnormal but quite normal behavior. You don't have to worry.

    It is true that a ViewHolder will be recycled and won't be re-created again.

    However, multiple ViewHolders are needed to display multiple items on the app's screen. So there will a certain numbers of ViewHolders are created and for that onCreateViewHolder is called a certain times.

    And onBindViewHolder will be called infinitly whenever data is reset to one of ViewHolders.

    I examined this fact with test application like below:

    MainActivity:

    public class MainActivity extends AppCompatActivity {
        private static final String[] DATASET = new String[]{
                "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
                "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
            recyclerView.setHasFixedSize(true);
    
            LinearLayoutManager layoutManager = new LinearLayoutManager(this);
            recyclerView.setLayoutManager(layoutManager);
    
            MyAdapter myAdapter = new MyAdapter(DATASET);
            recyclerView.setAdapter(myAdapter);
        }
    }
    

    MyAdapter:

    public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
        private static final String LOG_TAG = "RecyclerViewAdapter";
        private String[] dataset;
    
        private int counterOnCreateViewHolder = 0;
        private int counterOnBindViewHolder = 0;
    
        public MyAdapter(String[] dataset) {
            Log.d(LOG_TAG, "Construct");
            this.dataset = dataset;
        }
    
        public static class ViewHolder extends RecyclerView.ViewHolder {
            public TextView textView;
            public ViewHolder(TextView textView) {
                super(textView);
                this.textView = textView;
            }
        }
    
        @Override
        public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            Log.d(LOG_TAG, "onCreateViewHolder (" + ++counterOnCreateViewHolder + ")");
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.adapter_textview, parent, false);
    
            ViewHolder viewHolder = new ViewHolder((TextView) view);
            return viewHolder;
        }
    
        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            Log.d(LOG_TAG, "onBindViewHolder (" + ++counterOnBindViewHolder + ")");
            holder.textView.setText(dataset[position]);
        }
    
        @Override
        public int getItemCount() {
            // Log.d(LOG_TAG, "getItemCount");
            return dataset.length;
        }
    }
    

    layout/activity_main.xml:

    <android.support.v7.widget.RecyclerView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        android:id="@+id/recycler_view" />
    

    layout/adapter_textview.xml:

    <TextView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/adapter_textview"
        android:textSize="30sp" />
    

    Result:

    09-22 06:03:04.166 D/RecyclerViewAdapter﹕ Construct
    09-22 06:03:05.179 D/RecyclerViewAdapter﹕ onCreateViewHolder (1)
    09-22 06:03:05.183 D/RecyclerViewAdapter﹕ onBindViewHolder (1)
    09-22 06:03:05.190 D/RecyclerViewAdapter﹕ onCreateViewHolder (2)
    09-22 06:03:05.192 D/RecyclerViewAdapter﹕ onBindViewHolder (2)
    09-22 06:03:05.192 D/RecyclerViewAdapter﹕ onCreateViewHolder (3)
    09-22 06:03:05.194 D/RecyclerViewAdapter﹕ onBindViewHolder (3)
    09-22 06:03:05.195 D/RecyclerViewAdapter﹕ onCreateViewHolder (4)
    09-22 06:03:05.197 D/RecyclerViewAdapter﹕ onBindViewHolder (4)
    09-22 06:03:05.198 D/RecyclerViewAdapter﹕ onCreateViewHolder (5)
    09-22 06:03:05.199 D/RecyclerViewAdapter﹕ onBindViewHolder (5)
    09-22 06:03:05.200 D/RecyclerViewAdapter﹕ onCreateViewHolder (6)
    09-22 06:03:05.202 D/RecyclerViewAdapter﹕ onBindViewHolder (6)
    09-22 06:03:05.203 D/RecyclerViewAdapter﹕ onCreateViewHolder (7)
    09-22 06:03:05.204 D/RecyclerViewAdapter﹕ onBindViewHolder (7)
    09-22 06:03:05.206 D/RecyclerViewAdapter﹕ onCreateViewHolder (8)
    09-22 06:03:05.207 D/RecyclerViewAdapter﹕ onBindViewHolder (8)
    09-22 06:03:05.209 D/RecyclerViewAdapter﹕ onCreateViewHolder (9)
    09-22 06:03:05.211 D/RecyclerViewAdapter﹕ onBindViewHolder (9)
    09-22 06:03:05.212 D/RecyclerViewAdapter﹕ onCreateViewHolder (10)
    09-22 06:03:05.213 D/RecyclerViewAdapter﹕ onBindViewHolder (10)
    09-22 06:03:05.215 D/RecyclerViewAdapter﹕ onCreateViewHolder (11)
    09-22 06:03:05.217 D/RecyclerViewAdapter﹕ onBindViewHolder (11)
    09-22 06:03:05.218 D/RecyclerViewAdapter﹕ onCreateViewHolder (12)
    09-22 06:03:05.220 D/RecyclerViewAdapter﹕ onBindViewHolder (12)
    09-22 06:03:55.048 D/RecyclerViewAdapter﹕ onCreateViewHolder (13)
    09-22 06:03:55.050 D/RecyclerViewAdapter﹕ onBindViewHolder (13)
    09-22 06:03:55.228 D/RecyclerViewAdapter﹕ onCreateViewHolder (14)
    09-22 06:03:55.229 D/RecyclerViewAdapter﹕ onBindViewHolder (14)
    09-22 06:03:55.230 D/RecyclerViewAdapter﹕ onCreateViewHolder (15)
    09-22 06:03:55.231 D/RecyclerViewAdapter﹕ onBindViewHolder (15)
    09-22 06:03:55.232 D/RecyclerViewAdapter﹕ onBindViewHolder (16)
    09-22 06:03:55.232 D/RecyclerViewAdapter﹕ onBindViewHolder (17)
    09-22 06:03:55.260 D/RecyclerViewAdapter﹕ onBindViewHolder (18)
    09-22 06:03:55.276 D/RecyclerViewAdapter﹕ onBindViewHolder (19)
    09-22 06:03:55.296 D/RecyclerViewAdapter﹕ onBindViewHolder (20)
    09-22 06:03:55.310 D/RecyclerViewAdapter﹕ onBindViewHolder (21)
    

    As you can see, only onBindViewHolder was called after onCreateViewHolder (15).