Android Advertencia: Ventana ya enfocada, ignorando la ganancia de enfoque

Necesito tus ojos, chicos. He luchado con mi código durante mucho tiempo, y todavía me quedo atrapado como un estante viejo.

Verá, hay numerosos temas relacionados con la advertencia de Android:

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

He leído un montón de ellos, no encontró nada útil y mis ojos están cansados.

Estoy trabajando en un componente spinner, cuyo primer elemento, llamado como Add new … dispara un cuadro de diálogo para agregar otro elemento a la lista. Debido a que actualmente tengo dos spinners (en una actividad), he creado una clase wrapper para los spinners, que se encarga de la lógica y he creado la clase, que se extiende DialogFragment ya que ambos hilanderos dispara un diálogo similar con <EditText> , sólo Diferentes títulos.

Pero desde el punto de vista, sólo funciona el primer spinner. El segundo hilandero, cuando choosig opción a Agregar nuevo … , no hace nada, sólo producir advertencia escrita anteriormente.

Spinner envoltura

Es la clase interna de KegAddActivity extends AppCompatActivity y se ve así:

 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

En el método onCreate() I instanciar hilanderos así

 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(); ... } 

Mi actual sospecha

Debido a que el primer hilandero funciona y el segundo no, y son bastante similares, creo que los hilanderos concurrentes para el enfoque de alguna manera, pero realmente no lo sé. He intentado reemplazar DialogFragment con Actividades separadas dedicadas a cada spinner y evento onItemSelected de spinners entonces llamado startActivityForResult() pero esto causó el mismo problema, el primer spinner funcionó bien y el segundo falló con la advertencia, por lo que el problema podría estar en código De hilanderos.

¡Finalmente algún progreso!

Por suerte, encontré la constelación donde funciona y luego fue capaz de averiguar por qué no.

Si el elemento de Agregar nuevo … está seleccionado actualmente en el hilandero y, a continuación, seleccione Agregar nuevo … , vuelva a producir ignoring focus gain advertencia de ignoring focus gain . Pero si selecciona algún otro elemento en la hiladora y luego selecciona Agregar nuevo … , funciona. El problema era, si no hay otros elementos en la hiladora, no puede realizar dicha reselección. Parece que el evento onItemSelected no se propaga, si selecciona una opción ya seleccionada. Pero esto es un problema importante, ya que el usuario puede pulsar Cancelar en AddNewDialog para volver a la vista principal y, a continuación, el Agregar nuevo … permanecerá seleccionado y podría ser la única opción, por lo que no hay forma de abrir AddNewDialog nuevo.

La solución, como hacerlo funcionar, es agregar otro elemento predeterminado, como Elegir de la lista … y si el usuario cancela el cuadro de diálogo, vuelva a seleccionar la opción de hiladora a la opción predeterminada. Lo probaré y mantendré este mensaje actualizado.

Conclusión

Si selecciona en el Spinner un elemento previamente seleccionado, el evento itemSelected no se propagará y W/InputMethodManagerService: Window already focused, ignoring focus gain advertencia de W/InputMethodManagerService: Window already focused, ignoring focus gain aparece en su registro.

Dado que Spinner no soporta el evento onItemClick , la única solución que encontré trabajando es definir una opción predeterminada Elija de la lista … y si el usuario cancela AddNewDialog el detector onDialogNegativeClick restablece el hilador al valor predeterminado Elija desde … el elemento, On Add new … hay cambio en la selección y el evento se propaga.

Encontramos el mismo problema y determinamos que la única manera alrededor de esto era crear un Spinner de encargo que llama a onItemSelected() incluso si el mismo artículo fue seleccionado:

 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()); } } } } 
  • Elemento giratorio simple de Android
  • Diseño personalizado para el elemento Spinner
  • Cómo agregar una pista en spinner en XML
  • Spinner.setSelection no activa OnItemSelectedListener correctamente
  • Cambiar el color del divisor de Spinner
  • Crear un hilandero por programación android
  • Cómo cambiar el color del divisor de spinner en android?
  • ¿El tamaño del texto de Spinner no cambia?
  • Añade más espacio entre los elementos de Android Spinner sin estilo personalizado?
  • Android - Eliminar Spinner Dropdown Arrow
  • Cómo agregar left drawable en Spinner View en Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.