【问题标题】:Error “java.lang.IllegalArgumentException: parameter must be a decendant of this view” occurs when first element of a RecyclerView is dismissed当 RecyclerView 的第一个元素被解除时,会出现错误“java.lang.IllegalArgumentException:参数必须是此视图的后代”
【发布时间】:2016-08-30 17:39:56
【问题描述】:

我一直在使用 ItemTouchHelper 类来为 RecyclerView 中的行启用“滑动删除”。它在大多数情况下运行良好,但是当我关闭第一行时,我的应用程序总是崩溃并出现“java.lang.IllegalArgumentException: parameter must be a decendant of this view”错误。

由于每一行都包含可聚焦的组件(EditTexts 和 ImageButtons),事情变得复杂了。我看到this question 解决了同样的错误,所以 我想我遇到了类似的聚焦问题。 为了修复错误,我覆盖了 RecyclerViewAdapter 中的 onViewDetachedFromWindow 以在每个视图组分离时清除焦点:

@Override
public void onViewDetachedFromWindow(ViewHolder holder) {
    int position = holder.getAdapterPosition();
    Log.d(TAG, "onViewDetachedFromWindow (" + position + ")");
    holder.mViewGroup.clearFocus();
    super.onViewDetachedFromWindow(holder);
}

它没有解决问题。现在我不知道如何继续。有没有其他人遇到过类似的问题,有没有人知道为什么这个错误只会在关闭第一行时发生?

带有错误和调试日志消息的堆栈跟踪(当存在两行时滑动第一行):

D/ItemTouchHelperCallback: onSwiped
D/ExerciseSessionAdapter: onItemDismiss (0)
D/ExerciseSession: removeSet
D/ExerciseSession: refreshCurrentSetIndex
D/ActiveExerciseSession: onExerciseSessionUpdate
D/ActiveExerciseSession: refreshFab
D/ExerciseSession: isCompleted
D/ExerciseSession: getNumSets
D/ExerciseSessionAdapter: getItemCount
D/ExerciseSession: getNumSets
D/TestItemTouchHelper: getItemOffsets
D/TestItemTouchHelper: getItemOffsets
D/ExerciseSessionAdapter: getItemCount
D/ExerciseSession: getNumSets
D/ExerciseSessionAdapter: getItemCount
D/ExerciseSession: getNumSets
D/ExerciseSessionAdapter: getItemViewType
D/ExerciseSessionAdapter: onBindViewHolder
D/ExerciseSession: getSet
D/ExerciseSession: getCurrentSetIndex
D/ExerciseSession: isCompleted
D/ExerciseSession: hasCategory
D/SetMeasurementChangedListener: setMeasurementChangedListener
D/ButtonEditText: setOnNumberChangedListener
D/ButtonEditText: setNumber
D/ButtonEditText: getNumberString
D/ButtonEditText: onNumberChanged
D/SetMeasurementChangedListener: numberChanged
D/ExerciseSession: getSet
D/ButtonEditText: getNumber
D/ExerciseSession: hasCategory
D/SetMeasurementChangedListener: setMeasurementChangedListener
D/ButtonEditText: setOnNumberChangedListener
D/ButtonEditText: setNumber
D/ButtonEditText: getNumberString
D/ButtonEditText: onNumberChanged
D/SetMeasurementChangedListener: numberChanged
D/ExerciseSession: getSet
D/ButtonEditText: getNumber
D/ExerciseSession: hasCategory
D/ExerciseSession: hasCategory
D/ExerciseSessionAdapter: onBindViewHolder (0)
D/ExerciseSessionAdapter: onViewAttachedToWindow (0)
D/TestItemTouchHelper: onChildViewAttachedToWindow
D/TestItemTouchHelper: getItemOffsets
D/ExerciseSessionAdapter: getItemCount
D/ExerciseSession: getNumSets
D/ExerciseSessionAdapter: getItemCount
D/ExerciseSession: getNumSets
D/ExerciseSessionAdapter: getItemViewType
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main

    Process: edu.umn.paull011.evolveworkoutlogger, PID: 14405
java.lang.IllegalArgumentException: parameter must be a descendant of this view
at android.view.ViewGroup.offsetRectBetweenParentAndChild(ViewGroup.java:5334)
at android.view.ViewGroup.offsetDescendantRectToMyCoords(ViewGroup.java:5263)
at android.widget.ScrollView.isWithinDeltaOfScreen(ScrollView.java:1161)
at android.widget.ScrollView.onSizeChanged(ScrollView.java:1566)
at android.view.View.sizeChange(View.java:16748)
at android.view.View.setFrame(View.java:16710)
at android.view.View.layout(View.java:16627)
at android.view.ViewGroup.layout(ViewGroup.java:5437)
at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1079)
at android.view.View.layout(View.java:16630)
at android.view.ViewGroup.layout(ViewGroup.java:5437)
at android.support.design.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.java:1092)
at android.support.design.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.java:802)
at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:816)
at android.view.View.layout(View.java:16630)
at android.view.ViewGroup.layout(ViewGroup.java:5437)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
at android.view.View.layout(View.java:16630)
at android.view.ViewGroup.layout(ViewGroup.java:5437)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1495)
at android.view.View.layout(View.java:16630)
at android.view.ViewGroup.layout(ViewGroup.java:5437)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
at android.view.View.layout(View.java:16630)
at android.view.ViewGroup.layout(ViewGroup.java:5437)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1495)
at android.view.View.layout(View.java:16630)
at android.view.ViewGroup.layout(ViewGroup.java:5437)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
at com.android.internal.policy.PhoneWindow$DecorView.onLayout(PhoneWindow.java:2678)
at android.view.View.layout(View.java:16630)
at android.view.ViewGroup.layout(ViewGroup.java:5437)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2171)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1931)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6013)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:606)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

初始化 RecyclerView:

public class ExerciseSessionSetsFragment extends Fragment {
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
        ...
        mRecyclerView.setHasFixedSize(false);

        // use a linear layout manager
        mLayoutManager = new LinearLayoutManager(getActivity());
        mRecyclerView.setLayoutManager(mLayoutManager);

        // specify an adapter
        mAdapter = new ExerciseSessionAdapter(this.getContext(), mExerciseSession);
        mRecyclerView.setAdapter(mAdapter);

        // add ItemTouchHelperCallBack to RecyclerView
        ItemTouchHelper.Callback callback = new ItemTouchHelperCallback(mAdapter);
        ItemTouchHelper touchHelper = new TestItemTouchHelper(callback); //Prints log messages
        touchHelper.attachToRecyclerView(mRecyclerView);
        ...
    }
}

OnItemDismiss 回调:

public class ExerciseSessionAdapter extends RecyclerView.Adapter<ExerciseSessionAdapter.ViewHolder>
implements ItemTouchHelperAdapter{
    ...
    @Override
    public void onItemDismiss(int position) {
        Log.d(TAG,"onItemDismiss");
        mExerciseSession.removeSet(position);
        notifyItemRemoved(position);
        notifyItemRangeChanged(position, mExerciseSession.getNumSets() - position);
    }
    ...
}

任何建议将不胜感激!

【问题讨论】:

    标签: java android


    【解决方案1】:

    如果有人遇到同样的问题,我设法通过对我的 onItemDismiss 方法进行小调整来解决我的问题。该错误是由 notifyItemRangeChanged 方法在解除的项目位于零位置时创建的。我改为使用 notifyDataSetChanged 方法来解决问题:

    @Override
    public void onItemDismiss(int position) {
        Log.d(TAG, "onItemDismiss");
        mExerciseSession.removeSet(position);
        notifyItemRemoved(position);
        if (position != 0) {
            notifyItemRangeChanged(position, mExerciseSession.getNumSets() - position);
        }
        else {
            notifyDataSetChanged();
        }
    }
    

    【讨论】:

    • 你用这个解决方案真的为我节省了几个小时!我想知道 Android 团队是否甚至知道这个内部错误......
    猜你喜欢
    • 1970-01-01
    • 2022-10-11
    • 1970-01-01
    • 1970-01-01
    • 2011-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-10
    相关资源
    最近更新 更多