问题1:最近在项目中遇到一个 物理键盘焦点异常 的问题,每次切换item的时候,焦点总会跳到第一个item的位置,看来看去,原来是这个界面使用了 RecycleView 的问题。在更新数据的时候,调用了 RecyclerViewAdapter.notifyDataSetChanged(),更新了所有item。
解决方法:只更新被选中的item ,调用 RecyclerViewAdapter.notifyItemChanged(index)
切记,要更新的 item 的位置(index)一定要准确,不然找不到指定更新的item,导致调用 RecyclerViewAdapter.notifyItemChanged(index)后,无法正常回调 Adapter方法的 onBindViewHolder(Holder, int)方法
然后发现,焦点问题解决了,新的问题又又又叕来了。。。
问题2:选择item 之后,图片会闪有木有,当然这个问题也不是很难,网上所搜一堆解决方法
解决方法:调用 RecyclerViewAdapter.notifyItemChanged(index, -1)
当然有的解决方案是通过屏蔽动画的方式,来解决刷新时闪动的问题。
((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
但是这个不是闪动的根本原因。下面来看看为什么 图片会闪动一下:
我们先看看 notifyItemChanged(int index) 的源码
RecycleView.java
/**
* Notify any registered observers that the item at <code>position</code> has changed.
* Equivalent to calling <code>notifyItemChanged(position, null);</code>.
*
* <p>This is an item change event, not a structural change event. It indicates that any
* reflection of the data at <code>position</code> is out of date and should be updated.
* The item at <code>position</code> retains the same identity.</p>
*
* @param position Position of the item that has changed
*
* @see #notifyItemRangeChanged(int, int)
*/
public final void notifyItemChanged(int position) {
mObservable.notifyItemRangeChanged(position, 1);
}
public void notifyItemRangeChanged(int positionStart, int itemCount) {
notifyItemRangeChanged(positionStart, itemCount, null);
}
public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
// since onItemRangeChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload);
}
}
Equivalent to calling notifyItemChanged(position, null);
.
– 从第二行的说明可以看出,调用notifyItemChanged(int position)等效调用notifyItemChanged(position, null);
具体通过 notifyItemRangeChanged 的 payload 传入 null,接着我们看下notifyItemChanged(int position, Object payload)
RecyclerView.java
/**
* Notify any registered observers that the item at <code>position</code> has changed with an
* optional payload object.
*
* <p>This is an item change event, not a structural change event. It indicates that any
* reflection of the data at <code>position</code> is out of date and should be updated.
* The item at <code>position</code> retains the same identity.
* </p>
*
* <p>
* Client can optionally pass a payload for partial change. These payloads will be merged
* and may be passed to adapter's {@link #onBindViewHolder(ViewHolder, int, List)} if the
* item is already represented by a ViewHolder and it will be rebound to the same
* ViewHolder. A notifyItemRangeChanged() with null payload will clear all existing
* payloads on that item and prevent future payload until
* {@link #onBindViewHolder(ViewHolder, int, List)} is called. Adapter should not assume
* that the payload will always be passed to onBindViewHolder(), e.g. when the view is not
* attached, the payload will be simply dropped.
*
* @param position Position of the item that has changed
* @param payload Optional parameter, use null to identify a "full" update
*
* @see #notifyItemRangeChanged(int, int)
*/
public final void notifyItemChanged(int position, Object payload) {
mObservable.notifyItemRangeChanged(position, 1, payload);
}
- A notifyItemRangeChanged() with null payload will clear all existing payloads on that item.
—notifyItemRangeChanged() 传入 null payload,会把已经存在的payload清除。 - 从这个注释“@param payload Optional parameter, use null to identify a “full” update” 可以看出 如果传入的payload为null,会进行完全更新。
综上,如果调用notifyItemChanged(int position),等效调用notifyItemChanged(position, null),当payload的 参数为 null 时,会进行全局刷新。