控件 -- RecyclerView

一、概念

从Android 5.0开始,谷歌公司推出了一个用于展示大量数据的新控件RecylerView,可以用来代替传统的ListView,更加强大和灵活。RecyclerView的出现会让很多开源项目被废弃,例如横向滚动的ListView、横向滚动的GridView、瀑布流控件,因为RecyclerView能够实现所有这些功能。

二、特点

  • RecyclerView封装了ViewHolder的回收复用,也就是说RecyclerView标准化了ViewHolder,编写Adapter面向的是ViewHolder而不再是View了,复用的逻辑被封装了,写起来更加简单,并且直接省去了ListView中convertView.setTag(holder)和convertView.getTag()这些繁琐的步骤。
  • 提供了一种插拔式的体验,高度解耦,非常灵活,RecyclerView专门抽取出了相应的类来控制Item的显示,使其扩展性非常强。
  • 设置布局管理器以控制Item的布局方式,横向、竖向以及瀑布流方式。例如:你想控制横向或者纵向滑动列表效果可以通过LinearLayoutManager这个类来进行控制(与GridView效果对应的是GridLayoutManager,与瀑布流对应的是StaggeredGridLayoutManager等),也就是说RecyclerView不再拘泥于ListView的线性展示方式,它也可以实现GridView等多种效果。
  • 可设置Item的间隔样式(可绘制),通过继承RecyclerView的ItemDecoration这个类,然后针对自己的业务需求去编写代码。
  • 可以控制Item增删的动画,可以通过ItemAnimator这个类进行控制,当然针对增删的动画,RecyclerView有其自己默认的实现。
  • 关于Item的点击和长按事件,需要用户自己去实现。

ListView相比RecyclerView,有一些优点:

  • addHeaderView()、addFooterView()添加头视图和尾视图。
  • 通过"android:divider"设置自定义分割线。
  • setOnItemClickListener()和setOnItemLongClickListener()设置点击事件和长按事件。

这些功能在RecyclerView中都没有直接的接口,要自己实现,虽然实现起来也很简单。

RecyclerView相比ListView,有一些优点:

  • 默认已经实现了View的复用,不需要类似if(convertView == null)的实现,而且回收机制更加完善。
  • 默认支持局部刷新。
  • 容易实现添加item、删除item的动画效果。
  • 容易实现拖拽、侧滑删除等功能。

RecyclerView是一个插件式的实现,对各个功能进行解耦,从而扩展性比较好。

三、基本使用

//build.gradle
apply plugin: 'com.android.application'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.0"
    defaultConfig {
        applicationId "com.example.sourcecodetest"
        minSdkVersion 19
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

    implementation 'androidx.recyclerview:recyclerview:1.0.0'
}

//Fruit
public class Fruit {
    private String name;
    private int imageId;

    public Fruit(String name, int imageId) {
        this.name = name;
        this.imageId = imageId;
    }

    public String getName() {
        return name;
    }

    public int getImageId() {
        return imageId;
    }
}

//fruit_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"/>
</LinearLayout>

//FruitAdapter
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
    private static final String TAG = "FruitAdapter";
    private List<Fruit> mFruitList;

    static class ViewHolder extends RecyclerView.ViewHolder {
        View fruitView;
        ImageView fruitImage;
        TextView fruitName;

        public ViewHolder(View view) {
            super(view);
            fruitView = view;
            fruitImage = view.findViewById(R.id.fruit_image);
            fruitName = view.findViewById(R.id.fruit_name);
        }
    }

    public FruitAdapter(List<Fruit> fruitList) {
        mFruitList = fruitList;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        Log.d(TAG, "zwm, onCreateViewHolder, viewType: " + viewType);
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.fruit_item, parent, false);
        final ViewHolder holder = new ViewHolder(view);
        holder.fruitView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int position = holder.getAdapterPosition();
                Fruit fruit = mFruitList.get(position);
                Log.d(TAG, "zwm, 你点击了View: " + fruit.getName());
            }
        });
        holder.fruitImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int position = holder.getAdapterPosition();
                Fruit fruit = mFruitList.get(position);
                Log.d(TAG, "zwm, 你点击了图片: " + fruit.getName());
            }
        });
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Fruit fruit = mFruitList.get(position);
        holder.fruitImage.setImageResource(fruit.getImageId());
        holder.fruitName.setText(fruit.getName());
        Log.d(TAG, "zwm, onBindViewHolder, position: " + position + ", fruit: " + fruit.getName());
    }

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

//activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

//MainActivity
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private List<Fruit> fruitList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        initFruits();
        RecyclerView recyclerView = findViewById(R.id.recycler_view);
        LinearLayoutManager layoutManager= new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter adapter = new FruitAdapter(fruitList);
        recyclerView.setAdapter(adapter);
    }

    private void initFruits() {
        Fruit fruit = new Fruit("苹果", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("香蕉", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("西瓜", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("龙眼", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("荔枝", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("樱桃", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("核桃", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("橙子", R.drawable.ic_launcher);
        fruitList.add(fruit);
    }
}

//输出log
2020-01-20 15:24:17.578 6404-6404/? D/MyApplication: zwm, onCreate
2020-01-20 15:24:17.803 6404-6404/? D/MainActivity: zwm, onCreate
2020-01-20 15:24:17.969 6404-6404/? D/FruitAdapter: zwm, onCreateViewHolder, viewType: 0
2020-01-20 15:24:17.979 6404-6404/? D/FruitAdapter: zwm, onBindViewHolder, position: 0, fruit: 苹果
2020-01-20 15:24:17.983 6404-6404/? D/FruitAdapter: zwm, onCreateViewHolder, viewType: 0
2020-01-20 15:24:17.989 6404-6404/? D/FruitAdapter: zwm, onBindViewHolder, position: 1, fruit: 香蕉
2020-01-20 15:24:17.991 6404-6404/? D/FruitAdapter: zwm, onCreateViewHolder, viewType: 0
2020-01-20 15:24:17.996 6404-6404/? D/FruitAdapter: zwm, onBindViewHolder, position: 2, fruit: 西瓜
2020-01-20 15:24:17.998 6404-6404/? D/FruitAdapter: zwm, onCreateViewHolder, viewType: 0
2020-01-20 15:24:18.003 6404-6404/? D/FruitAdapter: zwm, onBindViewHolder, position: 3, fruit: 龙眼
2020-01-20 15:24:18.006 6404-6404/? D/FruitAdapter: zwm, onCreateViewHolder, viewType: 0
2020-01-20 15:24:18.010 6404-6404/? D/FruitAdapter: zwm, onBindViewHolder, position: 4, fruit: 荔枝
2020-01-20 15:24:18.013 6404-6404/? D/FruitAdapter: zwm, onCreateViewHolder, viewType: 0
2020-01-20 15:24:18.021 6404-6404/? D/FruitAdapter: zwm, onBindViewHolder, position: 5, fruit: 樱桃
2020-01-20 15:24:18.023 6404-6404/? D/FruitAdapter: zwm, onCreateViewHolder, viewType: 0
2020-01-20 15:24:18.028 6404-6404/? D/FruitAdapter: zwm, onBindViewHolder, position: 6, fruit: 核桃
2020-01-20 15:24:20.364 6404-6404/com.example.sourcecodetest D/FruitAdapter: zwm, onCreateViewHolder, viewType: 0
2020-01-20 15:24:20.370 6404-6404/com.example.sourcecodetest D/FruitAdapter: zwm, onBindViewHolder, position: 7, fruit: 橙子
2020-01-20 15:24:28.299 6404-6404/com.example.sourcecodetest D/FruitAdapter: zwm, 你点击了View: 西瓜
2020-01-20 15:24:34.295 6404-6404/com.example.sourcecodetest D/FruitAdapter: zwm, 你点击了图片: 荔枝

四、LayoutManager

LayoutManager负责RecyclerView的布局,其中包含了Item View的获取与回收。
RecyclerView提供了三种布局管理器:

  • LinearLayoutManager:以垂直或者水平列表方式展示Item。
  • GridLayoutManager:以网格方式展示Item。
  • StaggeredGridLayoutManager:以瀑布流方式展示Item。

GridLayoutManager常用构造方法:

//spanCount,每列或者每行的item个数,设置为1,就是列表样式
//该构造函数默认是竖直方向的网格样式
GridLayoutManager(Context context, int spanCount)

//spanCount,每列或者每行的item个数,设置为1,就是列表样式
//网格样式的方向,水平(OrientationHelper.HORIZONTAL)或者竖直(OrientationHelper.VERTICAL)
//reverseLayout,是否逆向,true:布局逆向展示,false:布局正向显示
GridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout)

StaggeredGridLayoutManager常用构造方法:

//spanCount代表每行或每列的Item个数,orientation代表列表的方向,竖直或者水平
StaggeredGridLayoutManager(int spanCount, int orientation)

五、Item Decoration & Item Animator

//MainActivity
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private RecyclerView recyclerView;
    private FruitAdapter adapter;
    private List<Fruit> fruitList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        initFruits();
        recyclerView = findViewById(R.id.recycler_view);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.addItemDecoration(new DividerItemDecoration(this, RecyclerView.VERTICAL));
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        adapter = new FruitAdapter(fruitList);
        recyclerView.setAdapter(adapter);
    }

    private void initFruits() {
        Fruit fruit = new Fruit("苹果", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("香蕉", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("西瓜", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("龙眼", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("荔枝", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("樱桃", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("核桃", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("橙子", R.drawable.ic_launcher);
        fruitList.add(fruit);
    }
}

六、HeaderView & FooterView

//fruit_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"/>
</LinearLayout>

//header_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:id="@+id/header_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="This is header item"/>
</RelativeLayout>

//footer_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:id="@+id/footer_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="This is footer item"/>
</RelativeLayout>

//FruitAdapter
public class FruitAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static final String TAG = "FruitAdapter";
    private static final int HEADER = 0;
    private static final int CONTENT = 1;
    private static final int FOOTER = 2;
    private List<Fruit> mFruitList;

    private static class ContentViewHolder extends RecyclerView.ViewHolder {
        View fruitView;
        ImageView fruitImage;
        TextView fruitName;

        public ContentViewHolder(View view) {
            super(view);
            fruitView = view;
            fruitImage = view.findViewById(R.id.fruit_image);
            fruitName = view.findViewById(R.id.fruit_name);
        }
    }

    private static class HeaderViewHolder extends RecyclerView.ViewHolder {

        public HeaderViewHolder(View itemView) {
            super(itemView);
        }
    }

    private static class FooterViewHolder extends RecyclerView.ViewHolder {

        public FooterViewHolder(View itemView) {
            super(itemView);
        }
    }

    public FruitAdapter(List<Fruit> fruitList) {
        mFruitList = fruitList;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        Log.d(TAG, "zwm, onCreateViewHolder, viewType: " + viewType);
        if(viewType == HEADER) {
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.header_item, parent, false);
            final HeaderViewHolder holder = new HeaderViewHolder(view);
            return holder;
        } else if(viewType == FOOTER) {
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.footer_item, parent, false);
            final FooterViewHolder holder = new FooterViewHolder(view);
            return holder;
        } else {
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.fruit_item, parent, false);
            final ContentViewHolder holder = new ContentViewHolder(view);
            holder.fruitView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    int position = holder.getAdapterPosition();
                    Fruit fruit = mFruitList.get(position);
                    Log.d(TAG, "zwm, 你点击了View: " + fruit.getName());
                }
            });
            holder.fruitImage.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    int position = holder.getAdapterPosition();
                    Fruit fruit = mFruitList.get(position);
                    Log.d(TAG, "zwm, 你点击了图片: " + fruit.getName());
                }
            });
            return holder;
        }
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if(holder instanceof HeaderViewHolder) {
            Log.d(TAG, "zwm, onBindViewHolder HeaderViewHolder, position: " + position);
        } else if(holder instanceof FooterViewHolder) {
            Log.d(TAG, "zwm, onBindViewHolder FooterViewHolder, position: " + position);
        } else {
            int index = position - 1;
            Fruit fruit = mFruitList.get(index);
            ((ContentViewHolder)holder).fruitImage.setImageResource(fruit.getImageId());
            ((ContentViewHolder)holder).fruitName.setText(fruit.getName());
            Log.d(TAG, "zwm, onBindViewHolder ContentViewHolder, position: " + position + ", index: " + index + ", fruit: " + fruit.getName());
        }
    }

    @Override
    public int getItemCount() {
        int itemCount = getContentItemCount() + 2;
        Log.d(TAG, "zwm, getItemCount: " + itemCount);
        return itemCount;
    }

    public int getContentItemCount(){
        int contentItemCount = mFruitList.size();
        Log.d(TAG, "zwm, getContentItemCount: " + contentItemCount);
        return contentItemCount;
    }

    @Override
    public int getItemViewType(int position) {
        int itemViewType;
        if(position == 0){
            itemViewType = HEADER;
        } else if(position == getContentItemCount() + 1){
            itemViewType = FOOTER;
        } else{
            itemViewType = CONTENT;
        }
        Log.d(TAG, "zwm, getItemViewType: " + itemViewType);
        return itemViewType;
    }
}

//MainActivity
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private RecyclerView recyclerView;
    private FruitAdapter adapter;
    private List<Fruit> fruitList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        initFruits();
        recyclerView = findViewById(R.id.recycler_view);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.addItemDecoration(new DividerItemDecoration(this, RecyclerView.VERTICAL));
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        adapter = new FruitAdapter(fruitList);
        recyclerView.setAdapter(adapter);
    }

    private void initFruits() {
        Fruit fruit = new Fruit("苹果", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("香蕉", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("西瓜", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("龙眼", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("荔枝", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("樱桃", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("核桃", R.drawable.ic_launcher);
        fruitList.add(fruit);
        fruit = new Fruit("橙子", R.drawable.ic_launcher);
        fruitList.add(fruit);
    }
}

//输出log
2020-01-20 19:56:25.254 28840-28840/? D/MyApplication: zwm, onCreate
2020-01-20 19:56:26.751 28840-28840/com.example.sourcecodetest D/MainActivity: zwm, onCreate
2020-01-20 19:56:27.628 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.628 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemCount: 10
2020-01-20 19:56:27.628 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.629 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemCount: 10
2020-01-20 19:56:27.629 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.629 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemCount: 10
2020-01-20 19:56:27.629 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemViewType: 0
2020-01-20 19:56:27.629 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onCreateViewHolder, viewType: 0
2020-01-20 19:56:27.886 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onBindViewHolder HeaderViewHolder, position: 0
2020-01-20 19:56:27.890 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.890 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemCount: 10
2020-01-20 19:56:27.890 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.890 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemViewType: 1
2020-01-20 19:56:27.890 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onCreateViewHolder, viewType: 1
2020-01-20 19:56:27.904 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onBindViewHolder ContentViewHolder, position: 1, index: 0, fruit: 苹果
2020-01-20 19:56:27.909 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.909 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemCount: 10
2020-01-20 19:56:27.909 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.909 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemViewType: 1
2020-01-20 19:56:27.909 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onCreateViewHolder, viewType: 1
2020-01-20 19:56:27.916 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onBindViewHolder ContentViewHolder, position: 2, index: 1, fruit: 香蕉
2020-01-20 19:56:27.919 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.919 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemCount: 10
2020-01-20 19:56:27.919 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.919 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemViewType: 1
2020-01-20 19:56:27.919 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onCreateViewHolder, viewType: 1
2020-01-20 19:56:27.926 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onBindViewHolder ContentViewHolder, position: 3, index: 2, fruit: 西瓜
2020-01-20 19:56:27.929 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.929 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemCount: 10
2020-01-20 19:56:27.929 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.929 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemViewType: 1
2020-01-20 19:56:27.929 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onCreateViewHolder, viewType: 1
2020-01-20 19:56:27.935 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onBindViewHolder ContentViewHolder, position: 4, index: 3, fruit: 龙眼
2020-01-20 19:56:27.938 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.938 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemCount: 10
2020-01-20 19:56:27.938 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.938 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemViewType: 1
2020-01-20 19:56:27.938 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onCreateViewHolder, viewType: 1
2020-01-20 19:56:27.944 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onBindViewHolder ContentViewHolder, position: 5, index: 4, fruit: 荔枝
2020-01-20 19:56:27.947 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.947 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemCount: 10
2020-01-20 19:56:27.947 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.947 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemViewType: 1
2020-01-20 19:56:27.948 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onCreateViewHolder, viewType: 1
2020-01-20 19:56:27.953 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onBindViewHolder ContentViewHolder, position: 6, index: 5, fruit: 樱桃
2020-01-20 19:56:27.956 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.956 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemCount: 10
2020-01-20 19:56:27.956 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:27.956 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemViewType: 1
2020-01-20 19:56:27.956 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onCreateViewHolder, viewType: 1
2020-01-20 19:56:27.963 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onBindViewHolder ContentViewHolder, position: 7, index: 6, fruit: 核桃
2020-01-20 19:56:30.637 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:30.637 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemCount: 10
2020-01-20 19:56:30.637 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:30.637 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemViewType: 1
2020-01-20 19:56:30.637 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onCreateViewHolder, viewType: 1
2020-01-20 19:56:30.644 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onBindViewHolder ContentViewHolder, position: 8, index: 7, fruit: 橙子
2020-01-20 19:56:30.651 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:30.651 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemCount: 10
2020-01-20 19:56:30.651 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:30.651 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemViewType: 1
2020-01-20 19:56:30.665 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:30.665 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemCount: 10
2020-01-20 19:56:30.665 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:30.665 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemViewType: 1
2020-01-20 19:56:30.683 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:30.683 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemCount: 10
2020-01-20 19:56:30.683 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:30.683 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemViewType: 2
2020-01-20 19:56:30.683 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onCreateViewHolder, viewType: 2
2020-01-20 19:56:30.689 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, onBindViewHolder FooterViewHolder, position: 9
2020-01-20 19:56:30.697 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:30.697 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemCount: 10
2020-01-20 19:56:30.697 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getContentItemCount: 8
2020-01-20 19:56:30.697 28840-28840/com.example.sourcecodetest D/FruitAdapter: zwm, getItemViewType: 2

相关链接

ListView和RecyclerView原理简析
基于滑动场景解析RecyclerView的回收复用机制原理

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容