programing

"IllegalArgumentException : 매개 변수는이 뷰의 하위 항목이어야합니다."오류 방지 / 캐치

firstcheck 2021. 1. 18. 08:05
반응형

"IllegalArgumentException : 매개 변수는이 뷰의 하위 항목이어야합니다."오류 방지 / 캐치


내부에 포커스 가능한 구성 요소가있는 ListView가 있습니다 (주로 EditTexts). 예, 이것이 정확히 권장되지는 않는다는 것을 알고 있지만 일반적으로 거의 모든 것이 잘 작동하며 초점은 이동해야하는 곳으로 이동합니다 (코드를 약간 수정해야 함). 어쨌든 내 문제는 손가락으로 목록을 스크롤 하고 IME 키보드가 표시 될 때 갑자기 트랙볼을 사용할 때 이상한 경쟁 조건이 있다는 것 입니다. 무언가가 경계를 벗어나 재활용 offsetRectBetweenParentAndChild()되어야하며 , 그 지점에서 메서드가 시작되어 IllegalArgumentException.

문제는이 예외가 내가 아는 한 try / catch를 삽입 할 수있는 모든 블록 외부에서 발생한다는 것입니다. 따라서이 질문에 대한 두 가지 유효한 해결책이 있습니다.

  1. 이 예외가 발생하는 이유 와 발생을 중지하는 방법을 알고있는 사람
  2. 누군가는 적어도 내 응용 프로그램이 살아남을 수 있도록 try / catch 블록을 어딘가에 배치하는 방법을 알고 있습니다. 내가 아는 한 문제는 초점의 문제이므로 내 응용 프로그램을 죽이지 않아야합니다 (그것이하는 일입니다). ViewGroup의 메서드를 재정의하려고 시도 했지만이 두 offset*메서드는 최종적으로 표시됩니다.

스택 추적 :

08-17 18:23:09.825: ERROR/AndroidRuntime(1608): FATAL EXCEPTION: main
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): java.lang.IllegalArgumentException: parameter must be a descendant of this view
08-17 18:23:09.825: ERROR/AndroidRuntime(1608):     at android.view.ViewGroup.offsetRectBetweenParentAndChild(ViewGroup.java:2633)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608):     at android.view.ViewGroup.offsetDescendantRectToMyCoords(ViewGroup.java:2570)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608):     at android.view.ViewRoot.scrollToRectOrFocus(ViewRoot.java:1624)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608):     at android.view.ViewRoot.draw(ViewRoot.java:1357)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608):     at android.view.ViewRoot.performTraversals(ViewRoot.java:1258)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1859)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608):     at android.os.Handler.dispatchMessage(Handler.java:99)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608):     at android.os.Looper.loop(Looper.java:130)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608):     at android.app.ActivityThread.main(ActivityThread.java:3683)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608):     at java.lang.reflect.Method.invokeNative(Native Method)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608):     at java.lang.reflect.Method.invoke(Method.java:507)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608):     at dalvik.system.NativeStart.main(Native Method)

죄송합니다. 이전 답변이이 문제를 해결하는 가장 완벽한 방법이 아니라는 것을 알았습니다.

그래서 나는 이것을 시도합니다 :
ListView가 스크롤을 시작할 때 ScrollListener를 Activity에 추가하고 현재 포커스를 지 웁니다.

protected class MyScrollListener implements OnScrollListener {

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
            // do nothing 
        }

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            if (SCROLL_STATE_TOUCH_SCROLL == scrollState) {
                View currentFocus = getCurrentFocus();
                if (currentFocus != null) {
                    currentFocus.clearFocus();
                }
            }
        }

    }

Bruce의 답변 은 문제를 해결 하지만 UX에 해를 끼치는 매우 잔인한 방식으로 처리합니다. 스크롤을하면 모든 뷰의 초점이 명확 해집니다.

문제의 증상을 다루지 만 실제 원인을 해결하지는 못합니다.

문제를 재현하는 방법 :

EditText에 포커스가 있고 키보드가 열리면 EditText가 화면에서 벗어날 때까지 스크롤하고 지금 표시되는 새 EditText로 재활용되지 않았습니다.

이 문제가 발생하는 이유를 먼저 이해하겠습니다.

ListView는 뷰를 재활용하고 모두가 알고있는 것처럼 다시 사용하지만 때로는 화면에서 즉시 사라진 뷰를 사용할 필요가 없어 나중에 사용할 수 있도록 유지하고 더 이상 표시 할 필요가 없기 때문입니다. 해당 view.mParent가 null이되도록 분리합니다. 그러나 키보드는 입력을 전달하는 방법을 알아야하며 초점을 맞춘보기 또는 정확한 EditText를 선택하여 수행합니다.

따라서 문제는 포커스가있는 EditText가 있지만 갑자기 부모가 없어서 "매개 변수는이 뷰의 자손이어야합니다."오류가 발생한다는 것입니다.

스크롤 리스너를 사용하면 더 많은 문제가 발생합니다.

해결책:

뷰가 사이드 힙으로 이동하고 더 이상 연결되지 않을 때 알려주는 이벤트를 수신해야합니다. 운 좋게도 ListView는이 이벤트를 노출합니다.

listView.setRecyclerListener(new AbsListView.RecyclerListener() {
        @Override
        public void onMovedToScrapHeap(View view) {
            if ( view.hasFocus()){
                view.clearFocus(); //we can put it inside the second if as well, but it makes sense to do it to all scraped views
                //Optional: also hide keyboard in that case
                if ( view instanceof EditText) {
                    InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                    imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
                }
            }
        }
    });

이 시도

 @Override
public View getView(int position, View convertView, ViewGroup parent) {
    //abandon current focus
    View currentFocus = ((Activity)mContext).getCurrentFocus();
    if (currentFocus != null) {
        currentFocus.clearFocus();
    }

    // other code
}

편집하다:

참조 : 더 나은 솔루션


가치가있는 것 (또는 이것에 대해 우연히 발견 한 사람)을 위해이 활동에 대한 ListView 접근 방식을 포기했습니다. 무작위 충돌을 제외하고 windowSoftInputMode="adjustPan"는 다른 웜 캔을 여는 을 설정하지 않고 초점 동작을 올바르게 얻는 것은 거의 불가능합니다 . 대신 "간단한"ScrollView를 사용했고 그 결과는 훌륭했습니다.


저도 같은 문제에 직면하고이 솔루션을 발견 -에 OnGroupCollapseListener/OnGroupExpandListenerOnScrollListener위해 ExpandableListView내가 명확 Focuse입니다 및 숨기기 강제 키보드. 또한 manifest활동 을 설정하는 것을 잊지 마십시오 windowSoftInputMode="adjustPan".

    expListView.setOnGroupCollapseListener(new OnGroupCollapseListener() {

        @Override
        public void onGroupCollapse(int groupPosition) {
            InputMethodManager inputManager = (InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            if (getWindow().getCurrentFocus() != null) {
                inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
                getCurrentFocus().clearFocus();
            }
        }
    });

    expListView.setOnGroupExpandListener(new OnGroupExpandListener() {

        @Override
        public void onGroupExpand(int groupPosition) {
            InputMethodManager inputManager = (InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            if (getWindow().getCurrentFocus() != null) {
                inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
                getCurrentFocus().clearFocus();
            }
        }
    });

    expListView.setOnScrollListener(new OnScrollListener() {

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            InputMethodManager inputManager = (InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            if (getCurrentFocus() != null) {
                inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
                getCurrentFocus().clearFocus();
            }
        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}

    });

정확히 OnGroupExpandListener필요한지, 아니면 쓸모가 없을지 모르겠습니다 .


나는 약간의 조정으로 bruce의 대답을 사용했습니다.

I needed adjustResize in my activity instead of adjustpan but when I tried it the error occurred again.
I replaced ScrollView with <android.support.v4.widget.NestedScrollView and it works fine now. Hope this helps someone!


I faced that problem, too, and the solution by validcat worked for me, but I had to call getWindow().getCurrentFocus().clearFocus().


I have the simplest but not good solution. Just extend the NestedScrollView and override onSizeChanged method, add a try catch block.

public class FixFocusErrorNestedScrollView extends NestedScrollView {

    public FixFocusErrorNestedScrollView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        try {
            super.onSizeChanged(w, h, oldw, oldh);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

In my case, I have tow layer view, top layer is listView, bottom is NestedScrollView. The error is happend when I switch the layer. The focus be taked by ListeView item (button).

So I can't make button lose focus. Then the best solution is extends NestedScrollView.


In case of Expandable List View, if your child items have edit text then you need to change the focusability before descendants for Expandable List View

expandableListView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);

I faced the same problem when using EditText in Recyclerview. After a lot of struggle and trying different option i found out the after deleting the row when my keyboard is opened produces this issue. I solved it by force closing my keyboard and changing notifyItemRemoved(position) with notifyDataSetChanged().


In my case it was related to windowSoftInputMode="adjustPan", listView and editText on list element (header view).

In order to fix that I call hide soft keyboard method before activity is finished.

public void hideKeyboard(Activity activity) {
    InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
    View focusView = activity.getCurrentFocus();
    if (focusView != null) {
        inputMethodManager.hideSoftInputFromWindow(focusView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }
}

If none of the solutions suggested here apply to you...

I've experienced a similar error and noticed it was reported by my users' devices (after a crash) without any clear explanation on what was causing it (same as the log shown on the question) - more specifically the issue only happened on Samsung Galaxy (including S6) devices (but not on Nexus devices or others, which is why my testing initially failed to reveal the issue). So, first, it is worth checking if the issue is device specific or not.

What I later found is that when pressing the back button while a Samsung virtual keyboard was displayed on a text field, the application would crash throwing this error - but not always!

Indeed, the text field causing the crash also happened to be displayed within a scrollview with fillViewPort="true" enabled.

What I found is that removing the fillViewPort option from the scrollview would not conflict with the Samsung keyboard being displayed/hidden. I suspect the issue is partly due to the fact that Samsung keyboards are different virtual keyboards than the stock Nexus keyboards, which is why only a subset of my users were experiencing the issue and it would crash on their devices only.

As a general rule, and if none of the other solutions suggested here apply to you, I would check if the issue is device specific, and also attempt to simplify the view I am working on until I can find the "culprit component" (component and view that, I should add, wasn't reported in the crash logs - so I only stumbled on the specific view causing the issue by chance!).

Sorry I cannot be more specific, but I hope this gives some pointers for further investigation if someone experience a similar but unexplained issue.


My answer is related to most of the answers here, but I just wanted to add that in my case, this crash occurred due to removing a row with an edit text that currently had the focus.

So all I did was override the remove method of the adapter, and queried whether the removed row contains the current focus edit and if so, clear the focus.

That solved it for me.


Based on @Bruce answer, can resolve error with recyclerview like this:

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View currentFocus = ((Activity)context).getCurrentFocus();
        if (currentFocus != null) {
            currentFocus.clearFocus();
        }
}

I'm using RecyclerView and none of the presented solutions worked. I got the error when removing items.

What did work was overriding the Adapter's 'onItemDismiss(int position)' so that it first does a 'notifyDataSetChanged()' prior to removing the item and then does 'notifyItemRemoved(position)' after removing the item. Like this:

// Adapter code
@Override
public void onItemDismiss(int position) {
    if (position >= 0 && getTheList() != null && getTheList().size() > position) {
        notifyDataSetChanged();  // <--- this fixed it.
        getTheList().remove(position);
        scrollToPosition(position);
        notifyItemRemoved(position);
    }
}

Also do an Override of 'removeAt(int position)' in the TabFragment to invoke the new cleanup code, like this:

// TabFragment code
@Override
public void removeAt(int position) {
    mAdapter.onItemDismiss(position);
    mAdapter.notifyItemRemoved(position); // <--- I put an extra notify here too
}

ReferenceURL : https://stackoverflow.com/questions/7100555/preventing-catching-illegalargumentexception-parameter-must-be-a-descendant-of

반응형