public class SelectedBean {
private boolean isSelected;
public boolean isSelected() {
return isSelected;
}
public void setSelected(boolean selected) {
isSelected = selected;
}
}
Acitivity 和Adapter其他方法都是最普通的不再赘述。
Adapter的onBindViewHolder()
如下:
Log.d(“TAG”, “onBindViewHolder() called with: holder = [” + holder + “], position = [” + position + “]”);
holder.ivSelect.setSelected(mDatas.get(position).isSelected());//“CheckBox”
holder.tvCoupon.setText(mDatas.get(position).getName());//TextView
holder.ivSelect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//实现单选,第一种方法,十分简单, Lv Rv通用,因为它们都有notifyDataSetChanged()方法
// 每次点击时,先将所有的selected设为false,并且将当前点击的item 设为true, 刷新整个视图
for (TestBean data : mDatas) {
data.setSelected(false);
}
mDatas.get(position).setSelected(true);
notifyDataSetChanged();
}
});
ViewHolder:
public static class CouponVH extends RecyclerView.ViewHolder {
private ImageView ivSelect;
private TextView tvCoupon;
public CouponVH(View itemView) {
super(itemView);
ivSelect = (ImageView) itemView.findViewById(R.id.ivSelect);
tvCoupon = (TextView) itemView.findViewById(R.id.tvCoupon);
}
}
方案优点:
简单粗暴
方案缺点:
其实需要修改的Item只有两项:
一个当前处于选中状态的Item->普通状态
再将当前手指点击的这个Item->选中状态
但采用普通方案,则会刷新整个一屏可见的Item,重走他们的getView()/onBindViewHolder()
方法。
其实一个屏幕一般最多可见10+个Item,遍历一遍也无伤大雅。
但咱们还是要有追求优雅的心,所以我们继续往下看。
2 利用Rv的notifyItemChanged()定向刷新:
本方案可以中速阅读
⑴本方案需要在Adapter里新增一个字段:
private int mSelectedPos = -1;//实现单选 方法二,变量保存当前选中的position
⑵在设置数据集时(构造函数,setData()方法等:),初始化 mSelectedPos
的值。
//实现单选方法二: 设置数据集时,找到默认选中的pos
for (int i = 0; i < mDatas.size(); i++) {
if (mDatas.get(i).isSelected()) {
mSelectedPos = i;
}
}
⑶onClick里代码如下:
//实现单选方法二: notifyItemChanged() 定向刷新两个视图
//如果勾选的不是已经勾选状态的Item
if (mSelectedPos!=position){
//先取消上个item的勾选状态
mDatas.get(mSelectedPos).setSelected(false);
notifyItemChanged(mSelectedPos);
//设置新Item的勾选状态
mSelectedPos = position;
mDatas.get(mSelectedPos).setSelected(true);
notifyItemChanged(mSelectedPos);
}
本方案由于调用了notifyItemChanged()
,所以还会伴有“白光一闪”的动画。
方案优点:
本方案,较优雅了,不会重走一屏可见的Item的getView()/onBindViewHolder()
方法,
但仍然会重走需要修改的两个Item的getView()/onBindViewHolder()
方法,
方案缺点:
我们实际上需要修改的,只是里面“CheckBox”的值,
按照在DiffUtil一文学习到的姿势,术语应该是“Partial bind “,
(安利时间,没听过DiffUtil和Partial bind的 戳->:【Android】详解7.0带来的新工具类:DiffUtil)
我们需要的只是部分绑定。
一个疑点:
使用方法2 在第一次选中其他Item时,切换selected状态时,
查看log,并不是只重走了新旧Item的onBindViewHolder()
方法,还走了两个根本不在屏幕范围里的Item的onBindViewHolder()
方法,
如,本例中 在还有item 0-3 在屏幕里,默认勾选item1,我选中item0后,log显示postion 4,5,0,1 依次执行了onBindViewHolder()
方法。
但是再次切换其他Item时, 会符合预期:只走需要修改的两个Item的getView()/onBindViewHolder()
方法。
原因未知,有朋友知道烦请告知,多谢。
3 Rv 实现部分绑定(推荐):
利用RecyclerView的 findViewHolderForLayoutPosition()
方法,获取某个postion的ViewHolder,按照源码里这个方法的注释,它可能返回null。所以我们需要注意判空,(空即在屏幕不可见)。
与方法2只有onClick里的代码不一样,核心还是利用mSelectedPos
字段搞事情。
//实现单选方法三: RecyclerView另一种定向刷新方法:不会有白光一闪动画 也不会重复onBindVIewHolder
CouponVH couponVH = (CouponVH) mRv.findViewHolderForLayoutPosition(mSelectedPos);
if (couponVH != null) {//还在屏幕里
couponVH.ivSelect.setSelected(false);
}else {
//add by 2016 11 22 for 一些极端情况,holder被缓存在Recycler的cacheView里,
//此时拿不到ViewHolder,但是也不会回调onBindViewHolder方法。所以add一个异常处理
notifyItemChanged(mSelectedPos);
}
mDatas.get(mSelectedPos).setSelected(false);//不管在不在屏幕里 都需要改变数据
//设置新Item的勾选状态
mSelectedPos = position;
mDatas.get(mSelectedPos).setSelected(true);
holder.ivSelect.setSelected(true);
方案优点:
定向刷新两个Item,只修改必要的部分,不会重走onBindViewHolder()
,属于手动部分绑定。代码量也适中,不多。
方案缺点:
没有白光一闪动画???(如果这算缺点)
4 Rv 利用payloads实现部分绑定(不推荐):
本方案属于开拓思维,是在方案2的基础上,利用payloads和notifyItemChanged(int position, Object payload)
搞事情。
不知道payloads是什么的,看不懂此方案的,我又要安利:(戳->:【Android】详解7.0带来的新工具类:DiffUtil)
onClick代码如下:
//实现单选方法四:
if (mSelectedPos != position) {
//先取消上个item的勾选状态
mDatas.get(mSelectedPos).setSelected(false);
//传递一个payload
Bundle payloadOld = new Bundle();
payloadOld.putBoolean(“KEY_BOOLEAN”, false);
notifyItemChanged(mSelectedPos, payloadOld);
//设置新Item的勾选状态
mSelectedPos = position;
mDatas.get(mSelectedPos).setSelected(true);
Bundle payloadNew = new Bundle();
payloadNew.putBoolean(“KEY_BOOLEAN”, true);
notifyItemChanged(mSelectedPos, payloadNew);
}
需要重写三参数的onBindViewHolder()
方法:
@Override
public void onBindViewHolder(CouponVH holder, int position, List payloads) {
if (payloads.isEmpty()) {
onBindViewHolder(holder, position);
} else {
Bundle payload = (Bundle) payloads.get(0);
if (payload.containsKey(“KEY_BOOLEAN”)) {
boolean aBoolean = payload.getBoolean(“KEY_BOOLEAN”);
holder.ivSelect.setSelected(aBoolean);
}
}
}
方案优点:
学习福利
【Android 详细知识点思维脑图(技能树)】
其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。
这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。
由于篇幅有限,这里以图片的形式给大家展示一小部分。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
由于篇幅有限,这里以图片的形式给大家展示一小部分。
[外链图片转存中…(img-lKMIqQnM-1714530573210)]
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!