Preventing/catching “IllegalArgumentException: parameter must be a descendant of this view” error

后端 未结 15 1479
北恋
北恋 2020-11-27 13:46

I have a ListView with some focusable components inside (mostly EditTexts). Yeah, I know this isn\'t exactly recommended, but in general, almost everything is w

相关标签:
15条回答
  • 2020-11-27 14:09

    For what it's worth (or whoever stumbles on this), I've abandoned the ListView approach for this Activity. Aside from the random crashes, it's almost impossible to get the focus behavior correctly without setting the windowSoftInputMode="adjustPan" which opens a bunch of other cans of worms. Instead, I just went for a "simple" ScrollView and that has been working great.

    0 讨论(0)
  • 2020-11-27 14:13

    I faced with the same problem and found out this solution - in OnGroupCollapseListener/OnGroupExpandListener and OnScrollListener for ExpandableListView i clear focuse and hide forced keyboard. Also do not forget to set in manifest for your activity 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) {}
    
        });
    

    I don't know exactly OnGroupExpandListener is needed or no, it could be useless.

    0 讨论(0)
  • 2020-11-27 14:13

    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.

    0 讨论(0)
  • 2020-11-27 14:15

    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.

    0 讨论(0)
  • 2020-11-27 14:15

    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
    }
    
    0 讨论(0)
  • 2020-11-27 14:17

    I am sorry to tell you, I found my previous answer isn't the most perfect way to solve this problem.

    So i try this :
    Append a ScrollListener to your Activity, when listView start scrolling, clear current focus.

    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();
                    }
                }
            }
    
        }
    
    0 讨论(0)
提交回复
热议问题