功能分类 | 公共内部接口 | 使用场景 |
---|---|---|
数据绑定 | onCreateViewHolder(ViewGroup parent, int viewType) | |
onBindViewHolder(VH holder, int position) | ||
getItemCount() | 创建和更新 ViewHolder 及其关联的视图 | |
数据变化 | notifyDataSetChanged() | |
notifyItemChanged(int position) | ||
notifyItemInserted(int position) | ||
notifyItemRemoved(int position) | ||
notifyItemMoved(int fromPosition, int toPosition) | ||
notifyItemRangeChanged(int positionStart, int itemCount) | ||
notifyItemRangeInserted(int positionStart, int itemCount) | ||
notifyItemRangeRemoved(int positionStart, int itemCount) | 通知 RecyclerView 数据集的变化,触发视图的重新绘制或布局 | |
数据观察 | registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer) | |
unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver observer) | 注册或取消注册观察者对象,监听数据集的变化 | |
数据标识 | setHasStableIds(boolean hasStableIds) | |
getItemId(int position) | 设置是否为每个列表项分配一个稳定的 ID,用于优化性能或实现动画效果 | |
视图类型 | getItemViewType(int position) | 返回给定位置的列表项的视图类型,用于支持不同的布局 |
RecyclerView.Adapter 是一个抽象类,它定义了 RecyclerView 的数据和视图的绑定器。它有三个抽象方法需要重写:
- onCreateViewHolder(ViewGroup parent, int viewType) :每当 RecyclerView 需要创建新的 ViewHolder 时,它都会调用此方法。此方法会创建并初始化 ViewHolder 及其关联的 View ,但不会填充视图的内容,因为 ViewHolder 此时尚未绑定到具体数据。
- onBindViewHolder(VH holder, int position) : RecyclerView 调用此方法将 ViewHolder 与数据相关联。此方法会提取适当的数据,并使用该数据填充 ViewHolder 的布局。
- getItemCount() : RecyclerView 调用此方法来获取数据集的大小。 RecyclerView 使用此方法来确定什么时候没有更多的列表项可以显示。
除了这三个抽象方法,RecyclerView.Adapter 还有一些公共方法、类、接口,它们的作用如下:
- setHasStableIds(boolean hasStableIds) :设置是否为每个列表项分配一个稳定的 ID。如果为 true ,则必须重写 getItemId(int position) 方法,以便为每个列表项返回一个唯一的 ID。
- getItemId(int position) :返回给定位置的列表项的 ID。如果 setHasStableIds(boolean hasStableIds) 设置为 false ,则默认返回 NO_ID 。如果设置为 true ,则必须重写此方法,以便为每个列表项返回一个唯一的 ID。
- getItemViewType(int position) :返回给定位置的列表项的视图类型。默认情况下,所有列表项都使用同一种视图类型。如果您想使用不同的视图类型,您可以重写此方法,并根据位置返回不同的整数值。
- notifyDataSetChanged() :通知 RecyclerView 数据集已经发生了变化,需要重新绘制所有列表项。
- notifyItemChanged(int position) :通知 RecyclerView 指定位置的列表项已经发生了变化,需要重新绘制该列表项。
- notifyItemInserted(int position) :通知 RecyclerView 在指定位置插入了一个新的列表项,需要重新计算布局。
- notifyItemRemoved(int position) :通知 RecyclerView 在指定位置删除了一个列表项,需要重新计算布局。
- notifyItemMoved(int fromPosition, int toPosition) :通知 RecyclerView 在指定位置之间移动了一个列表项,需要重新计算布局。
- notifyItemRangeChanged(int positionStart, int itemCount) :通知 RecyclerView 在指定范围内的列表项已经发生了变化,需要重新绘制这些列表项。
- notifyItemRangeInserted(int positionStart, int itemCount) :通知 RecyclerView 在指定范围内插入了一些新的列表项,需要重新计算布局。
- notifyItemRangeRemoved(int positionStart, int itemCount) :通知 RecyclerView 在指定范围内删除了一些列表项,需要重新计算布局。
- registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer) :注册一个观察者对象,用于监听数据集的变化。
- unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver observer) :取消注册一个观察者对象,不再监听数据集的变化。
RecyclerView.AdapterDataObserver 是一个抽象类,它定义了监听数据集变化的观察者。它有以下几个回调方法:
- onChanged() :当数据集发生任何变化时调用。
- onItemRangeChanged(int positionStart, int itemCount) :当指定范围内的列表项发生变化时调用。
- onItemRangeChanged(int positionStart, int itemCount, Object payload) :当指定范围内的列表项发生变化时调用。 payload 参数是一个可选的对象,用于传递部分更新的信息。
- onItemRangeInserted(int positionStart, int itemCount) :当指定范围内插入新的列表项时调用。
- onItemRangeRemoved(int positionStart, int itemCount) :当指定范围内删除列表项时调用。
- onItemRangeMoved(int fromPosition, int toPosition, int itemCount) :当指定范围内的列表项移动时调用。
局部刷新相关
notify 系列方法 | 功能 | 使用场景 | 搭配方法 |
---|---|---|---|
notifyDataSetChanged() | 通知 RecyclerView 数据集发生了任何变化,需要重新绘制所有列表项 | 当数据集发生了大量或不确定的变化时,或者不需要动画效果时 | 无 |
notifyItemChanged(int position) | 通知 RecyclerView 指定位置的列表项发生了变化,需要重新绘制该列表项 | 当数据集中某个元素的内容发生了变化时,或者需要显示某个元素的选中状态时 | onBindViewHolder(VH holder, int position) |
notifyItemChanged(int position, Object payload) | 通知 RecyclerView 指定位置的列表项发生了变化,需要重新绘制该列表项,并传递部分更新的信息 | 当数据集中某个元素只有部分内容发生了变化时,或者需要优化性能时 | onBindViewHolder(VH holder, int position, List payloads) |
notifyItemInserted(int position) | 通知 RecyclerView 在指定位置插入了一个新的列表项,需要重新计算布局,并显示插入动画效果 | 当数据集中增加了一个新元素时,或者需要显示插入动画效果时 | onCreateViewHolder(ViewGroup parent, int viewType) |
notifyItemRemoved(int position) | 通知 RecyclerView 在指定位置删除了一个列表项,需要重新计算布局,并显示删除动画效果 | 当数据集中删除了一个元素时,或者需要显示删除动画效果时 | 无 |
notifyItemMoved(int fromPosition, int toPosition) | 通知 RecyclerView 在指定位置之间移动了一个列表项,需要重新计算布局,并显示移动动画效果 | 当数据集中某个元素的位置发生了变化时,或者需要显示移动动画效果时 | 无 |
notifyItemRangeChanged(int positionStart, int itemCount) | 通知 RecyclerView 在指定范围内的列表项发生了变化,需要重新绘制这些列表项,并批量刷新多个列表项 | 当数据集中一段连续的元素内容发生了变化时,或者需要批量刷新时 | onBindViewHolder(VH holder, int position) |
notifyItemRangeChanged(int positionStart, int itemCount, Object payload) | 通知 RecyclerView 在指定范围内的列表项发生了变化,需要重新绘制这些列表项,并传递部分更新的信息,并批量刷新多个列表项 | 当数据集中一段连续的元素只有部分内容发生了变化时,或者需要优化性能时 | onBindViewHolder(VH holder, int position, List payloads) |
notifyItemRangeInserted(int positionStart, int itemCount) | 通知 RecyclerView 在指定范围内插入了一些新的列表项,需要重新计算布局,并批量插入多个列表项 | 当数据集中增加了一段连续的新元素时,或者需要批量插入时 | onCreateViewHolder(ViewGroup parent, int viewType) |
notifyItemRangeRemoved(int positionStart, int itemCount) | 通知 RecyclerView 在指定范围内删除了一些列表项,需要重新计算布局,并批量删除多个列表项 | 当数据集中删除了一段连续的元素时,或者需要批量删除时 | 无 |
notifyItemChanged(int position, Object payload) 局部刷新 UI 的例子。
这个方法的作用是通知 RecyclerView 指定位置的列表项发生了变化,需要重新绘制该列表项,并传递部分更新的信息。使用场景是当数据集中某个元素只有部分内容发生了变化时,或者需要优化性能时。
例如,假设您有一个 RecyclerView 显示了一些音乐播放列表,每个列表项包含了歌曲的标题、作者、时长和播放状态。当您点击某个列表项时,您想要改变它的播放状态,并显示一个播放图标。但是您不想要重新绘制整个列表项,因为其他信息没有变化。这时,您可以使用 notifyItemChanged(int position, Object payload) 方法来实现局部刷新。
具体的步骤如下:
- 在 Adapter 中定义一个 ViewHolder 类,它是一个封装了列表项布局的 View 的容器。您可以在 ViewHolder 的构造方法中初始化列表项的视图组件,并在 onBindViewHolder(VH holder, int position) 方法中为它们设置数据。
- 在 Adapter 中重写 onBindViewHolder(VH holder, int position, List payloads) 方法,它会在 notifyItemChanged(int position, Object payload) 方法被调用时触发。在这个方法中,您可以根据 payload 参数来判断是否需要局部刷新,以及如何刷新。如果 payload 参数为空或不符合您的要求,您需要调用 super.onBindViewHolder(holder,position, payloads) 方法来触发全局刷新。
- 在 Activity 或 Fragment 中为 RecyclerView 设置点击事件监听器,当某个列表项被点击时,获取它的位置和数据,并调用 notifyItemChanged(int position, Object payload) 方法来通知 Adapter 局部刷新。payload 参数可以是任何对象,您可以根据自己的需求来定义它。
以下是一个简单的示例代码
// 定义一个数据类
public class Song {
private String title; // 歌曲标题
private String artist; // 歌曲作者
private String duration; // 歌曲时长
private boolean playing; // 歌曲播放状态
public Song(String title, String artist, String duration, boolean playing) {
this.title = title;
this.artist = artist;
this.duration = duration;
this.playing = playing;
}
// 省略 getter 和 setter 方法
}
// 定义一个 Adapter 类
public class SongAdapter extends RecyclerView.Adapter<SongAdapter.SongViewHolder> {
private List<Song> songList; // 数据集
public SongAdapter(List<Song> songList) {
this.songList = songList;
}
// 定义一个 ViewHolder 类
public static class SongViewHolder extends RecyclerView.ViewHolder {
public TextView tvTitle; // 歌曲标题视图
public TextView tvArtist; // 歌曲作者视图
public TextView tvDuration; // 歌曲时长视图
public ImageView ivPlay; // 歌曲播放图标视图
public SongViewHolder(View view) {
super(view);
tvTitle = (TextView) view.findViewById(R.id.tv_title);
tvArtist = (TextView) view.findViewById(R.id.tv_artist);
tvDuration = (TextView) view.findViewById(R.id.tv_duration);
ivPlay = (ImageView) view.findViewById(R.id.iv_play);
}
}
@Override
public SongViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// 创建并返回 ViewHolder 对象
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.song_list_item, parent, false);
return new SongViewHolder(itemView);
}
@Override
public void onBindViewHolder(SongViewHolder holder, int position) {
// 为 ViewHolder 的视图组件设置数据
Song song = songList.get(position);
holder.tvTitle.setText(song.getTitle());
holder.tvArtist.setText(song.getArtist());
holder.tvDuration.setText(song.getDuration());
holder.ivPlay.setVisibility(song.isPlaying() ? View.VISIBLE : View.INVISIBLE);
}
@Override
public void onBindViewHolder(SongViewHolder holder, int position, List<Object> payloads) {
// 判断是否需要局部刷新
if (!payloads.isEmpty()) {
// 如果 payload 参数是一个布尔值,表示播放状态发生了变化
if (payloads.get(0) instanceof Boolean) {
boolean playing = (Boolean) payloads.get(0);
// 只刷新播放图标的可见性
holder.ivPlay.setVisibility(playing ? View.VISIBLE : View.INVISIBLE);
}
} else {
// 如果 payload 参数为空或不符合要求,调用全局刷新
super.onBindViewHolder(holder, position, payloads);
}
}
@Override
public int getItemCount() {
// 返回数据集的大小
return songList.size();
}
}
// 定义一个 Activity 或 Fragment 类
public class SongActivity extends AppCompatActivity {
private RecyclerView recyclerView; // RecyclerView 控件
private SongAdapter adapter; // Adapter 对象
private List<Song> songList; // 数据集
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_song);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
// 初始化数据集
songList = new ArrayList<>();
songList.add(new Song("Hello", "Adele", "4:55", false));
songList.add(new Song("Shape of You", "Ed Sheeran", "3:53", false));
songList.add(new Song("Despacito", "Luis Fonsi", "4:42", false));
songList.add(new Song("Bad Guy", "Billie Eilish", "3:14", false));
songList.add(new Song("Blinding Lights", "The Weeknd", "3:20", false));
// 创建并设置 Adapter 对象
adapter = new SongAdapter(songList);
recyclerView.setAdapter(adapter);
// 设置布局管理器和分割线
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
// 设置点击事件监听器
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getApplicationContext(), recyclerView, new RecyclerTouchListener.ClickListener() {
@Override
public void onClick(View view, int position) {
// 获取点击位置的数据对象
Song song = songList.get(position);
// 改变播放状态
song.setPlaying(!song.isPlaying());
// 通知 Adapter 局部刷新,并传递播放状态作为 payload 参数
adapter.notifyItemChanged(position, song.isPlaying());
}
@Override
public void onLongClick(View view, int position) {
}
}));
}
}
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓
PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题