RecyclerView.Adapter的onCreateViewHolder被调用两次或更多次,多次

hat*_*ata 15 android android-viewholder android-recyclerview

我目前正在开发一个使用RecyclerView的应用程序.

在查看LogCat时,我注意到onCreateViewHolder在实例化后被调用了两次.

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
Run Code Online (Sandbox Code Playgroud)

此外,onBindViewHolder被调用了两次,但我知道每当项目被回收时都会调用它.

但我认为onCreateViewHolder只需调用一次即可.

这种异常行为吗?如果是这样,怎么解决?

hat*_*ata 22

这不是异常,而是非常正常的行为.你不必担心.

确实,ViewHolder将被回收,不会再次重新创建.

但是,需要多个ViewHolders才能在应用程序的屏幕上显示多个项目.因此会创建一定数量的ViewHolders,因此onCreateViewHolder会被调用一定次数.

每当数据重置为ViewHolders之一时,onInStindViewHolder将被无限调用.

我用下面的测试应用程序检查了这个事实:

主要活动:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

布局/ 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" />
Run Code Online (Sandbox Code Playgroud)

布局/ 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" />
Run Code Online (Sandbox Code Playgroud)

结果:

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)
Run Code Online (Sandbox Code Playgroud)

如您所见,之后仅调用onBindViewHolder onCreateViewHolder (15).

  • 有没有办法处理 onBindViewHolder 方法的多次调用,因为我在滚动时遇到了性能问题。谢谢 (2认同)

小智 10

这是 RecyclerView 稳定视图的稳定答案

这些下面的行有助于垂直地在 recyclerview 中保持列表数据在我的垂直列表中只有 10 个我不想再次重新绑定的项目。每行都有无限的水平 RecyclerView 列表。

  1. mRecyclerview.getRecycledViewPool().setMaxRecycledViews(int viewtype,int itemsCount)

  2. mRecyclerview.setItemViewCacheSize(int itemsCount)

    这两种方法都有助于不回收垂直视图。但是如果列表太大,则会导致 OOM 错误,所以要小心实现它。

    Here 0 is viewType in Recyclerview adapter and 10 are the items count.
    
    mRecyclerview.getRecycledViewPool().setMaxRecycledViews(0, 10);
    mRecyclerview.setItemViewCacheSize(10);
    
    Run Code Online (Sandbox Code Playgroud)

  • setItemViewCacheSize(items.size) 对我有用,这对于嵌套的回收器视图很有用 (2认同)