对于那些没有使用 Kotlin 并且还在苦苦挣扎的人,我快速浏览了一下他们实现的 doOnNextLayout(crossinline action: (view: T) -> Unit) 解决方案,非常简单。
如果您不使用自定义 RecyclerView (CustomRecyclerView extends RecyclerView),您可能需要重新考虑它,因为这会带来很多您将来可能想要添加的好处(平滑滚动到位置、垂直分隔线等) ..)
CustomRecyclerView.class 内部
public void doOnNextLayout(Consumer<List<View>> onChange) {
addOnLayoutChangeListener(
new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
onChange.accept(getChildren());
removeOnLayoutChangeListener(this);
}
}
);
}
getChildren() 方法正在构建一个大小为 getChildCount(); 的列表;每次迭代都有一个 add(getChild(i)) 。
现在...
关于代码的一个重要方面是:removeOnLayoutChangeListener(this);
这意味着开发人员要求您在每次向适配器提交列表之前执行此操作。
理论上,我们只能在创建 RecyclerView 时将监听器放置一次(IMO 会更便宜/更好)+ 因为我们正在检索视图,所以我们可以使用 DataBindingUtils 检索它们各自的绑定。并通过其 DataBind 获取适配器在 onBind 上提供的任何数据。
要做到这一点,它需要更多的代码。
首先适配器需要知道它们所在的 Fragment,或者 RecyclerView::setAdapter 需要提供一个 ViewLifeCyclerOwner,第三个更简单的选择是为适配器提供一个 onViewDestroy() 方法,并在 Fragment 的 onDestroyView 上执行它() 方法。
@Override
public void onDestroyView() {
super.onDestroyView();
adater.onViewDestroyed();
}
通过覆盖 onAttachedToRecyclerView,我们可以将它们附加为观察者。
private final List<Runnable> submitter = new ArrayList<>();
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
if (recyclerView instanceof CustomRecyclerView) {
submitter.add(((CustomRecyclerView) recyclerView)::onSubmit);
}
}
CustomRecyclerView 端的 onSubmit 方法将提供一个布尔值,告诉 recyclerView 是否正在提交列表。
private boolean submitting;
public void doOnNextLayout(Consumer<List<View>> onChange) {
addOnLayoutChangeListener(
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
if (submitting) {
onChange.accept(getChildren());
submitting = false;
}
}
);
}
public void onSubmit() {
submitting = true;
}
每个 Runnable 都会在列表提交的那一刻被执行:
对于 ListAdapter,有 2 个可能的入口点:
private void notifyRVs() {
for (Runnable r:submitter
) {
r.run();
}
}
@Override
public void submitList(@Nullable List<X> list, @Nullable Runnable commitCallback) {
notifyRVs();
super.submitList(list, commitCallback);
}
@Override
public void submitList(@Nullable List<X> list) {
notifyRVs();
super.submitList(list);
}
现在为了防止内存泄漏,我们必须清除 ViewDestroyed() 上的 Runnables 列表
在适配器内部...
public void onViewDestroyed() {
submitter.clear();
}
现在因为方法的功能发生了变化,我们应该重命名它,并将 Consumer 与 LayoutChangeListener() 解耦
private Consumer<List<View>> onChange = views -> {};
public void setOnListSubmitted(Consumer<List<View>> onChange) {
this.onChange = onChange;
}
public CustomRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
//Read attributes
setOnListSubmissionListener();
}
private void setOnListSubmissionListener() {
addOnLayoutChangeListener(
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
if (submitting) {
onChange.accept(getChildren());
submitting = false;
}
}
);
}