Android 探究RecyclerView onViewAttachedToWindow 触发时机

网友投稿 1245 2022-11-14

Android 探究RecyclerView onViewAttachedToWindow 触发时机

Android 探究RecyclerView onViewAttachedToWindow 触发时机

文章目录

​​RecyclerView 基本使用​​​​FruitAdapter​​

​​Adapter中的 onAttachedToRecyclerView​​​​Adapter中的 onViewAttachedToWindow​​

​​瀑布流 `StaggeredGridLayoutManager` 设置第一个 item 占据一整行​​

RecyclerView 基本使用

​​activity_main.xml​​

​​item_layout.xml​​

​​Fruit​​

public class Fruit { private String fruitName; public String getFruitName() { return fruitName; } public Fruit(String fruitName) { this.fruitName = fruitName; } //获取数据 public static List initFruitList() { List fruitList = new ArrayList<>(); for (int i = 0; i < 20; i++) { Fruit apple = new Fruit("Item " + i); fruitList.add(apple); } return fruitList; }}

​​FruitAdapter​​

public class FruitAdapter extends RecyclerView.Adapter { private List mFruitList; public FruitAdapter(List fruitList) { mFruitList = fruitList; } @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false); ViewHolder viewHolder = new ViewHolder(view); return viewHolder; } @Override public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) { Fruit fruit = mFruitList.get(position); viewHolder.fruitName.setText(fruit.getFruitName()); } @Override public int getItemCount() { return mFruitList.size(); } public class ViewHolder extends RecyclerView.ViewHolder { TextView fruitName; public ViewHolder(@NonNull View itemView) { super(itemView); fruitName = itemView.findViewById(R.id.fruit_name); } } @Override public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) { super.onDetachedFromRecyclerView(recyclerView); } @Override public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); } @Override public void onViewAttachedToWindow(@NonNull ViewHolder holder) { super.onViewAttachedToWindow(holder); } @Override public void onViewDetachedFromWindow(@NonNull ViewHolder holder) { super.onViewDetachedFromWindow(holder); }}

​​MainActivity​​

class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding private var adapter: FruitAdapter? = null private var list = mutableListOf() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) list = Fruit.initFruitList() adapter = FruitAdapter(list) binding.fruitRecyclerView.layoutManager = LinearLayoutManager(this) binding.fruitRecyclerView.adapter = adapter }}

FruitAdapter

在上面,FruitAdapter 有四个方法

@Override public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) { super.onDetachedFromRecyclerView(recyclerView); } @Override public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); } @Override public void onViewAttachedToWindow(@NonNull ViewHolder holder) { super.onViewAttachedToWindow(holder); } @Override public void onViewDetachedFromWindow(@NonNull ViewHolder holder) { super.onViewDetachedFromWindow(holder); }

Adapter中的 onAttachedToRecyclerView

​​onAttachedToRecyclerView​​​ 、 ​​onDetachedFromRecyclerView​​​ 这两个方法是对于 ​​adapter​​​ 来说的,当 ​​adapter ​​​和 ​​recyclerView​​​ 进行绑定的时候会回调 ​​onAttachedToRecyclerView​​

什么时候会回调 ​​onDetachedFromRecyclerView​​ ?

答案:recyclerView 已经有 adapter 了,又绑定了一个新的 adapter ,就会执行 ​​onDetachedFromRecyclerView​​

对于一个 adapter 实例,​​onAttachedToRecyclerView​​​ 、 ​​onDetachedFromRecyclerView​​ 这两个方法只会回调一次。

源码分析:

​​onAttachedToRecyclerView​​​ 、 ​​onDetachedFromRecyclerView​​​ 在 ​​RecyclerView​​ 都是空方法。

首先看看 ​​RecyclerView​​​ 的 ​​setAdapter​​ 方法

​​setAdapter​​​ 方法里,调用 ​​setAdapterInternal​​ 方法

设置一个新的 ​​adapter​​​ , 如果 ​​recyclerView​​​ 已经绑定过 ​​adapter​​ 。

那么就对于老的​​adapter​​​调用 ​​onDetachedFromRecyclerView(this)​​

新的 ​​adapter ​​​调用 ​​onAttachedToRecyclerView(this)​​

Adapter中的 onViewAttachedToWindow

@Override public void onViewAttachedToWindow(@NonNull ViewHolder holder) { super.onViewAttachedToWindow(holder); int position = holder.getLayoutPosition(); Log.d("yu--", "attach " + position); } @Override public void onViewDetachedFromWindow(@NonNull ViewHolder holder) { super.onViewDetachedFromWindow(holder); int position = holder.getLayoutPosition(); Log.d("yu--", "detach " + position); }

​​RecyclerView ​​​本质上也是一个 ​​ViewGroup​​​,那么它的 ​​Item​​​ 要显示出来,自然需要 ​​addView() ​​​进来,移出的时候,当然也要 ​​removeView()​​​ 出去,所以对应的自然是 ​​onViewAttachedToWindow()​​​ 和 ​​onViewAttachedToWindow()​​ 了。

所以在特定场景下,可以通过这两个回调来解决少量 Item 移出屏幕,移进屏幕所需要的工作。为什么说特定场景下呢,由于假如调用了 ​​notifyDataSetChanged() ​​​ 方法的话,会触发当前在屏幕中的所有 Item 的 ​​onViewAttachedToWindow()​​ 。

当第一次 setAdapter 的时候,屏幕内所有 item 会调用 ​​onViewAttachedToWindow(ViewHolder holder) ​​ , 日志如下:

yu--: attach 0yu--: attach 1yu--: attach 2yu--: attach 3yu--: attach 4yu--: attach 5yu--: attach 6

调用 ​​notifyDataSetChanged​​​ ,屏幕类所有的 item 会先执行 ​​onViewDetachedFromWindow​​​ , 然后执行 ​​onViewAttachedToWindow​​

yu--: detach 6yu--: detach 5yu--: detach 4yu--: detach 3yu--: detach 2yu--: detach 1yu--: detach 0yu--: attach 0yu--: attach 1yu--: attach 2yu--: attach 3yu--: attach 4yu--: attach 5yu--: attach 6

综上,Adapter 的 ​​onViewAttachedToWindow​​ 适合做 item 曝光埋点,但是要注意,这个方法可能会执行多次。

瀑布流 StaggeredGridLayoutManager 设置第一个 item 占据一整行

@Override public void onViewAttachedToWindow(@NonNull ViewHolder holder) { super.onViewAttachedToWindow(holder); int position = holder.getLayoutPosition(); StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams(); if (position == 0) { //占据一整行 layoutParams.setFullSpan(true); } else { layoutParams.setFullSpan(false); } }

效果图:

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:SpringMVC+Vue项目图书推荐系统
下一篇:Cloud Foundry 2. 核心概念
相关文章

 发表评论

暂时没有评论,来抢沙发吧~