You*_*ode 22 android android-viewholder recycler-adapter android-recyclerview
我有一个包含13个项目的列表(虽然可以添加或删除项目),位置0-12.当首次显示包含RecyclerView的片段时,用户只能看到位置0到7(位置7只有一半可见).在我的适配器中,Log每次视图持有者被绑定/绑定(如果语法适用于此,则为idk)并记录其位置.
适配器
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
Log.d(TAG, "onBindViewHolder() position: " + position);
...
}
Run Code Online (Sandbox Code Playgroud)
从我Log看到0-7的位置是绑定的:
我有一个selectAll()方法,ViewHolder通过适配器位置获取每个.如果返回holder的不是null我,则使用返回holder来更新视图以显示它已被选中.如果返回的持有者是null我调用selectOnBind()一个方法来标记该位置的视图更新,以显示它在绑定时被选中而不是实时,因为它当前未显示:
public void selectAll() {
for (int i = 0; i < numberOfItemsInList; i++) {
MyAdapter.ViewHolder holder = (MyAdapter.ViewHolder)
mRecyclerView.findViewHolderForAdapterPosition(i);
Log.d(TAG, "holder at position " + i + " is " + holder);
if (holder != null) {
select(holder);
} else {
selectOnBind(i);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这种方法中我Log将holder与它的位置一起:
所以到目前为止,一切似乎都很正常.我们有0-7的位置显示,并根据Log这些位置限制.当我在selectAll()不改变可见视图(滚动)的情况下点击时,我看到定义0-7位置,8-12位置null.到现在为止还挺好.
这是有趣的地方.如果在调用后selectAll()我向下滚动列表位置8和9,则不显示它们被选中.
检查时,Log我发现它是因为它们从未被束缚,即使它们被报告为null:
更令人困惑的是,每次都不会发生这种情况.如果我首先启动应用程序并测试它可能会有效.但事后似乎没有失败.我猜这与被回收的观点有关,但即便如此,他们也不必受约束?
编辑(6-29-16)
AndroidStudio更新后我似乎无法重现该错误.它按照我的预期工作,绑定空视图.如果这个问题重新出现,我将回到这篇文章.
Ped*_*ira 17
发生这种情况是因为:
getChildAt不起作用,将为该位置返回null)onBind不会被调用) 通话recyclerView.setItemViewCacheSize(0)将解决这个"问题".
由于默认值为2(private static final int DEFAULT_CACHE_SIZE = 2;in RecyclerView.Recycler),因此您将始终获得2个不会调用onBind但未添加到回收站的视图
在您的情况下,位置8和9的视图未被回收,它们将从窗口分离并将再次附加.并且对于这些分离视图onBindViewHolder不被调用,仅onViewAttachedToWindow被调用.如果您在适配器中覆盖这些功能,您可以看到我在说什么.
@Override
public void onViewRecycled(ViewHolder vh){
Log.wtf(TAG,"onViewRecycled "+vh);
}
@Override
public void onViewDetachedFromWindow(ViewHolder viewHolder){
Log.wtf(TAG,"onViewDetachedFromWindow "+viewHolder);
}
Run Code Online (Sandbox Code Playgroud)
现在,为了解决您的问题,您需要跟踪应该回收但已分离的视图,然后执行您的部分过程
@Override
public void onViewAttachedToWindow(ViewHolder viewHolder){
Log.wtf(TAG,"onViewAttachedToWindow "+viewHolder);
}
Run Code Online (Sandbox Code Playgroud)
Pedro Oliveira 和 Zartha 的答案非常有助于理解问题,但我没有看到任何令我满意的解决方案。
我相信您有两个不错的选择,具体取决于您在做什么:
选项1
如果您想onBindViewHolder()调用屏幕外视图,而不管它是否已缓存/分离,那么您可以执行以下操作:
RecyclerView.ViewHolder view_holder = recycler_view.findViewHolderForAdapterPosition( some_position );
if ( view_holder != null )
{
//manipulate the attached view
}
else //view is either non-existant or detached waiting to be reattached
notifyItemChanged( some_position );
Run Code Online (Sandbox Code Playgroud)
这个想法是,如果视图被缓存/分离,那么notifyItemChanged()将告诉适配器视图无效,这将导致onBindViewHolder()被调用。
选项 2
如果您只想执行部分更改(而不是里面的所有内容onBindViewHolder()),那么在 of 内部onBindViewHolder( ViewHolder view_holder, int position ),您需要将 存储在position中view_holder,并在 中执行您想要的更改onViewAttachedToWindow( ViewHolder view_holder )。
为简单起见,我推荐选项 1,除非您onBindViewHolder()正在做一些密集的事情,比如弄乱位图。