Android警告:窗口已经聚焦,忽略焦点增益

伙计们,我需要你的眼睛.我已经用我的代码努力了很长时间,而且我仍然像旧机架一样陷入困境.

你看,有很多与android警告相关的主题:

W/InputMethodManagerService: Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub...

我读了很多,没有发现任何有用的东西,我的眼睛很累.

我正在处理一个微调器组件,第一个项目命名为Add new …激活一个Dialog以将另一个项目添加到列表中.因为我目前有两个这样的微调器(在一个活动中),我为微调器创建了一个包装器类,它负责逻辑并且我创建了类,它扩展了DialogFragment,因为两个微调器都用< EditText>激发类似的对话框,只是不同的标题.

但在视图中,只有第一个微调器工作.当选择Add new …时,第二个微调器没有任何作用,只产生上面写的警告.

旋转包装

KegAddActivity的内部类是否扩展了AppCompatActivity,如下所示:

public class ExtendableSpinner implements AdapterView.OnItemSelectedListener, View.OnTouchListener {
    private static final int ADD_NEW_ID = -1;

    private final Spinner _mSpinner;
    private final String _mTableName;
    private final int _mAddNewTitle;
    private final MatrixCursor _mAddOptionsCursor;

    private Uri _mAdapterUri;
    private SimpleCursorAdapter _mAdapter;
    private boolean _mWasTouched;

    public ExtendableSpinner(Spinner spinner, String tableName, int addNewTitle) {
        super();

        _mSpinner = spinner;
        _mTableName = tableName;
        _mAdapterUri = BeerBookUriHandler.getUri(tableName);
        _mAddNewTitle = addNewTitle;

        _mAddOptionsCursor = new MatrixCursor(new String[]{Table.COL_ID, BeerTable.COL_NAME});
        _mAddOptionsCursor.addRow(new String[]{"" + ADD_NEW_ID, getString(addNewTitle) + '\u2026'});

        _mSpinner.setOnTouchListener(this);
        _mSpinner.setOnItemSelectedListener(this);

    }

    public void setAdapterUri(Uri uri) {
        _mAdapterUri = uri;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        _mWasTouched = true;
        return false;
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        if (_mWasTouched) {
            // event fired by user
            if (id == ADD_NEW_ID) {
                Bundle args = new Bundle();
                args.putInt(AddNewDialogFragment.TITLE, _mAddNewTitle);

                _mAddNewDialogFragment = new AddNewDialogFragment();
                _mAddNewDialogFragment.setArguments(args);
                _mAddNewDialogFragment.show(getSupportFragmentManager(), _mTableName + "AddNewDialog");
            }
        } else {
            // event fired at activity start
            int selection = 0;
            if (_mAdapter.getCount() > 1) {
                selection = 1;
                Uri uri = BeerBookUriHandler.getUri(KegTable.NAME + "/last");
                Cursor cursor = getContentResolver().query(uri, new String[]{
                        _mTableName + "." + Table.COL_ID
                }, null, null, null);
                if (cursor != null && cursor.moveToFirst()) {
                    long lastUsedId = cursor.getLong(0);
                    selection = getPositionForId(lastUsedId);
                }
                cursor.close();
            }
            _mSpinner.setSelection(selection);
        }
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {

    }

    public void populate() {
        Cursor cursor = getContentResolver().query(_mAdapterUri,
                BEER_PROJECTION, null, null, BeerTable.COL_NAME);
        Cursor extendedCursor = new MergeCursor(new Cursor[]{ _mAddOptionsCursor, cursor});

        _mAdapter = new SimpleCursorAdapter(getApplicationContext(),
                SPINNER_LAYOUT, extendedCursor, new String[] { BeerTable.COL_NAME },
                new int[] {android.R.id.text1}, 0);
        _mAdapter.setDropDownViewResource(SPINNER_ITEM_LAYOUT);
        _mSpinner.setAdapter(_mAdapter);
    }

    public int getPositionForId(long itemId) {
        int pos = 0;
        for(int i = 1, l = _mAdapter.getCount(); i < l; i++)
            if (itemId == _mAdapter.getItemId(i)) {
                pos = i;
                break;
            }

        return pos;
    }

    public long getSelectedId() {
        return _mSpinner.getSelectedItemId();
    }

    public void setSelectionById(long id) {
        _mSpinner.setSelection(getPositionForId(id));
    }
}

KegAddActivity

在onCreate()方法中我像这样实例化微调器

protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ...

    final Spinner beerSpinner = (Spinner) findViewById(R.id.keg_add_beer);
    _mBeerSpinner = new ExtendableSpinner(beerSpinner, BeerTable.NAME, R.string.beer_add);
    // initially disable, wait for brewery selection
    beerSpinner.setEnabled(false);

    final Spinner brewerySpinner = (Spinner) findViewById(R.id.keg_add_brewery);
    _mBrewerySpinner = new ExtendableSpinner(brewerySpinner, BreweryTable.NAME, R.string.brewery_add) {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            super.onItemSelected(parent, view, position, id);
            if (id > 0) {
                // brewery selected, populate beerSpinner
                Uri uri = BeerBookUriHandler.getUri(BreweryTable.NAME + "/" +
                        getSelectedId() + "/" + BeerTable.NAME);
                _mBeerSpinner.setAdapterUri(uri);
                _mBeerSpinner.populate();
                beerSpinner.setEnabled(true);
            }
        }
    };
    _mBrewerySpinner.populate();

    ...
}

我目前的怀疑

因为第一个微调器工作而第二个旋转器没有和非常相似,我认为旋转器以某种方式同时聚焦,但我真的不知道.
我已经尝试将DialogFragment替换为专用于每个微调器的分离活动和旋转器的onItemSelected事件,然后调用startActivityForResult(),但这导致了同样的问题,第一个微调器工作正常,第二个微调失败并出现警告,因此问题可能出现在代码中纺纱厂

终于有了进步!

幸运的是,我找到了它工作的星座,然后能够找出它没有的原因.

如果当前在微调器中选择了“添加新…”项目,则再次选择“添加新…”项会产生忽略焦点增益警告.但是如果你在微调器中选择了一些其他项目,然后选择Add new …,它就可以了.问题是,如果微调器中没有其他项,则无法执行此类重选.如果选择已选择的选项,似乎不会传播onItemSelected事件.但这是一个主要问题,因为用户可以在AddNewDialog上点击Cancel返回主视图,然后Add new …将保持选中状态并且可能是唯一选项,因此无法再次打开AddNewDialog.

解决方案,如何使其工作,是添加另一个默认项,如从列表中选择…项,如果用户取消对话框,重新选择微调器到默认选项.我会测试它并保持这篇文章的更新.

结论

如果您从Spinner中选择之前选择的项目,则不会传播itemSelected事件,并且W / InputMethodManagerService:Window已经聚焦,忽略焦点增益警告将显示在您的日志中.

由于Spinner不支持onItemClick事件,我发现工作的唯一解决方法是定义一个默认选项从列表中选择…如果用户取消AddNewDialog,onDialogNegativeClick监听器会将微调器重置为默认选择…项目,因此在点击之后在添加新…选择发生变化,事件传播.

最佳答案 我们遇到了同样的问题并确定了解决这个问题的唯一方法是创建一个调用onItemSelected()的自定义Spinner,即使选择了相同的项:

public class CustomSpinner extends Spinner {

        public CustomSpinner(Context contextArg){
            super(contextArg);
        }

        public CustomSpinner(Context contextArg, AttributeSet attributeSetArg){
            super(contextArg, attributeSetArg);
        }

        public CustomSpinner(Context contextArg, AttributeSet attributeSetArg, int styleArg){
            super(contextArg, attributeSetArg, styleArg);
        }

        @Override
        public void setSelection(int positionArg){
            boolean samePosition = positionArg == getSelectedItemPosition();
            super.setSelection(positionArg, false);
            // here we modifiy the Spinner's default behavior
            if(samePosition){
                // we dispatch the event, even if the position is the same
                OnItemSelectedListener onItemSelectedListener = getOnItemSelectedListener();
                if(onItemSelectedListener != null){
                    onItemSelectedListener.onItemSelected(this,
                            getSelectedView(),
                            positionArg,
                            getSelectedItemId());
                }
            }
        }

        @Override
        public void setSelection(int positionArg, boolean animateArg){
            boolean samePosition = positionArg == getSelectedItemPosition();
            super.setSelection(positionArg, animateArg);
            // here we modifiy the Spinner's default behavior
            if(samePosition){
                // we dispatch the event, even if the position is the same
                OnItemSelectedListener onItemSelectedListener = getOnItemSelectedListener();
                if(onItemSelectedListener != null){
                    onItemSelectedListener.onItemSelected(this,
                            getSelectedView(),
                            positionArg,
                            getSelectedItemId());
                }
            }
        }
}
点赞