我正在开发Android应用程序,并在Play商店发布后,我很多时候都面临这个问题。
Exception java.lang.IndexOutOfBoundsException: Inconsistency detected.Invalid view holder adapter positionViewHolder{2f9d83c position=11 id=-1, oldPos=-1, pLpos:-1 no parent}
android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition (RecyclerView.java:5297)
android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline (RecyclerView.java:5479)
android.support.v7.widget.GapWorker.prefetchPositionWithDeadline (GapWorker.java:282)
android.support.v7.widget.GapWorker.flushTaskWithDeadline (GapWorker.java:336)
android.support.v7.widget.GapWorker.flushTasksWithDeadline (GapWorker.java:349)
android.support.v7.widget.GapWorker.prefetch (GapWorker.java:356)
android.support.v7.widget.GapWorker.run (GapWorker.java:387)
android.os.Handler.handleCallback (Handler.java:815)
android.os.Handler.dispatchMessage (Handler.java:104)
android.os.Looper.loop (Looper.java:207)
android.app.ActivityThread.main (ActivityThread.java:5737)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:789)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:679)
我长时间搜索了这个问题并应用了很多解决方案,但异常仍然提出
我申请的解决方案之一是制作自定义LinearLayoutManager:
public class WrapContentLinearLayoutManager extends LinearLayoutManager {
public WrapContentLinearLayoutManager(Context context) {
super(context);
}
//... constructor
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
super.onLayoutChildren(recycler, state);
setAutoMeasureEnabled(false);
} catch (IndexOutOfBoundsException e) {
Log.e("Error", "IndexOutOfBoundsException in RecyclerView happens");
}
}
public WrapContentLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
setAutoMeasureEnabled(false);
}
public WrapContentLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setAutoMeasureEnabled(false);
}
@Override
public boolean supportsPredictiveItemAnimations() {
return false;
}
}
在我的应用程序中依赖于RecyclerView,加载更多和滑动以刷新功能
我使用Volley从网络服务获取数据加载更多和滑动以刷新
在RecyclerView中加载更多项目,在Volley Response的回调中,我将新项目附加到ArrayList并通知适配器如下:
final int positionStart = list.size() - 1;
final int itemCount = response.length();
for (int i=0;i<response.length();i++)
{
try
{
obj = response.getJSONObject(i);
list.add(new ItemEntry(obj.getInt("Id"),obj.getString("Title").trim()obj.getBoolean("isFavorite"));
} catch (JSONException e) {
e.printStackTrace();
}
if(index == 0)
{
// for first Initialize for adapter
adapter = new MyAdapter(latestEntryList,getActivity());
adapter.setOnItemClickCallBack(mainFragment);
recyclerView.setAdapter(adapter);
}
else
{
// for load more items
recyclerView.post(new Runnable()
{
@Override
public void run()
{
adapter.updateItems(positionStart,itemCount);
}
});
}
}
Adapter.UpdateItems的代码
public void updateItems(int positionStart,int itemCount) {
itemsCount = getItemCount();
this.notifyItemRangeInserted(positionStart,itemCount);
}
如果是负载更多,我会执行以下操作;在OnRefresh
public void onRefresh() {
listFragment.LatestEntry(0,false);
// 0 the index and False isAppend to list of not
}
LatestEntry的代码是:
private void LatestEntry(final int index, final boolean isAppend)
{
String customerId = "123";
String uri = String.format(BASE_URL+"/api/Entry/LatestEntry?customerId=%s&index=%s",customerId,index);
JsonArrayRequest LatestEntryJsonArrayRequest = new JsonArrayRequest(Request.Method.GET, uri,
null, new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response)
{
JSONObject obj = new JSONObject();
if(response.length() > 0 && !isAppend)
{
int startPosition = 0;
int preSize;
if(adapter != null)
preSize = adapter.entries.size();
else
preSize = 0;
if(preSize > 0 && EntryList.size() > 0) {
EntryList.clear();
adapter.entries.clear();
adapter.notifyItemRangeRemoved(startPosition, preSize);
}
}
final int positionStart = EntryList.size() - 1;
final int itemCount = response.length();
for (int i=0;i<response.length();i++)
{
try {
obj = response.getJSONObject(i);
list.add(new ItemEntry
(obj.getInt("Id"),obj.getString("Title").trim()
obj.getBoolean("isFavorite"));
} catch (JSONException e) {
e.printStackTrace();
}
}
if(index == 0)
{ // for first Initialize for adapter
adapter = new MyAdapter(latestEntryList,getActivity());
adapter.setOnItemClickCallBack(mainFragment);
recyclerView.setAdapter(adapter);
}
else
{
// for load more items
recyclerView.post(new Runnable()
{
@Override
public void run() {
adapter.updateItems(positionStart,itemCount);
}
});
}
}
setListShownNoAnimation(true);
if(mainFragment.swipeRefreshLayout.isRefreshing())
mainFragment.swipeRefreshLayout.setRefreshing(false);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MyApplication.getAppContext(),error.getMessage(),Toast.LENGTH_LONG);
}
}
);
LatestEntryJsonArrayRequest.setTag("LatestEntry");
KidsSingleton.getInstance().addToRequestQueue(LatestEntryJsonArrayRequest);
}
请注意以下内容:
任何人都可以帮助解决这个问题吗?
答案 0 :(得分:1)
我有类似的情况 - viewpagers作为回收者视图的项目。添加\删除项目时,这些“等待删除”项目有一些动画。因此,当我调用删除项目时,动画仍在表演我有:
Post.joins(:tags).having('count(tags.id) > 3').group('posts.id')
为了避免这种异常,我创建了一个延迟删除项目的处理程序。但!这是错的。如果您已经更改了适配器RV的数据,则应该立即没有任何处理程序或多线程通知这些更改。 因此,请考虑将此方式更改为更新不需要单独线程的内容。
答案 1 :(得分:0)
RecyclerView$Recycler.validateViewHolderForOffsetPosition
抱怨未收到有效的ViewHolder
项,而它似乎位于第11项的偏移位置。
假设您在向适配器添加更多项目时可能忘记给ViewHolder
充气......处理方式似乎不对;普通的,只需要更新数据阵列,然后用例如通知适配器。 notifyDataChanged()
;在将项目直接添加到适配器时,可以考虑在内部触发这些通知。
swipeRefreshLayout.setRefreshing(false)
可能应该在回调方法中发生,以便在加载完成时轮子动画消失。
也许检查这个example以了解框架触发事件的顺序(因此通常是问题,一个人创建了框架已经带来的功能)...踩到可能还提供了一个线索,为什么没有有效的ViewHolder
为该项目充气。
答案 2 :(得分:0)
可能是您设置为适配器的列表已被更改,但notifyDataSetChanged尚未被调用。 就我而言,我延迟了对notifyDataSetChanged的调用。但是适配器的getItemCount()已更改为另一个值,因此崩溃。
答案 3 :(得分:-1)
致电notifyItemRangeChanged(positionStart,itemCount)
在致电notifyItemRangeInserted(positionStart,itemCount);
为我工作。