我需要你的眼睛,伙计们。我已经用我的代码争取了很长时间,而且我仍然像旧机架一样陷入困境。
你知道,有许多与android警告相关的主题:
W/InputMethodManagerService: Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub...
我读了很多,没有发现任何有用的东西,我的眼睛很累。
我正在处理一个微调器组件,第一个项目命名为添加新... 会触发一个对话框,将另一个项目添加到列表中。因为我目前有两个这样的微调器(在一个活动中),我为微调器创建了一个包装类,它负责逻辑和我创建的类,它扩展了DialogFragment
,因为两个微调器都触发类似的对话框使用<EditText>
,只是不同的标题。
但是在视图中,只有第一个微调器工作。第二个微调器,当选择添加新... 选项时,什么都不做,只产生上面写的警告。
是KegAddActivity extends 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));
}
}
在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()
,但这会导致同样的问题,第一个微调器工作良好,第二个警告失败,因此问题可能出在Spinners的代码中。
幸运的是,我找到了它工作的星座,然后才发现它为什么没有。
如果当前在微调器中选择了添加新... 的项目,则再次选择添加新... 项会产生ignoring focus gain
警告。但是如果您在微调器中选择其他项目,然后选择添加新... ,它就可以工作。问题是,如果微调器中没有其他项,则无法执行此类重选。如果选择已选择的选项,似乎不会传播onItemSelected
事件。但这是一个主要问题,因为用户可以在AddNewDialog
点击取消返回主视图,然后添加新... 将保持选中状态并且可能是唯一的选择,因此无法再次打开AddNewDialog
。
如何使其工作的解决方案是添加另一个默认项,例如从列表中选择... 项,如果用户取消对话框,则重新选择微调器到默认选项。我会对其进行测试并保持此帖更新。
如果您从之前选择的Spinner
项目中进行选择,则不会传播itemSelected
事件,并且会在您的日志中显示W/InputMethodManagerService: Window already focused, ignoring focus gain
警告。
由于Spinner
不支持onItemClick
事件,我找到的唯一解决方法是定义一个默认选项从列表中选择... ,如果用户取消AddNewDialog
onDialogNegativeClick
侦听器会将微调器重置为默认从... 项目中选择,因此在点击添加新... 之后,会发生更改选择和事件传播。
答案 0 :(得分:2)
我们遇到了同样的问题并确定了解决此问题的唯一方法是创建一个调用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());
}
}
}
}