MenuItemCompat.getActionView siempre devuelve nulo

142

Acabo de implementar la v7 AppCompatbiblioteca de soporte, pero MenuItemCompat.getActionViewsiempre devuelve nulo en cada versión de Android que probé (4.2.2, 2.3.4 ...)

El SearchViewse muestra en la barra de acción, pero no responde a las acciones táctiles y no se expande para mostrar su, EditTexty es como un simple icono.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu, menu);

    MenuItem searchItem = menu.findItem(R.id.action_search);
    SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
    if (searchView != null) {
        SearchViewCompat.setOnQueryTextListener(searchView, mOnQueryTextListener);
        searchView.setIconifiedByDefault(false);
        Log.d(TAG,"SearchView not null");
    } else
        Log.d(TAG, "SearchView is null");
    }
    return super.onCreateOptionsMenu(menu);
}

Menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">

    <item android:id="@+id/action_search"
          app:showAsAction="always|collapseActionView"
          android:icon="@drawable/abc_ic_search"
          android:title="@string/action_bar_search"
          android:actionViewClass="android.support.v7.widget.SearchView"/>

    <item android:id="@+id/action_refresh"
          android:icon="@drawable/refresh"
          android:title="@string/action_bar_refresh"
          app:showAsAction="ifRoom"/>
</menu>
Mohsen Afshin
fuente

Respuestas:

296

Finalmente encontré la solución.

  1. Cambiar el espacio de nombres de actionViewClassde android:actionViewClassaapp:actionViewClass

  2. Implementando android.support.v7.widget.SearchView.OnQueryTextListenerinterfaz para la actividad actual.

  3. Usar directamente en setOnQueryTextListenerlugar deSearchViewCompat.setOnQueryTextListener

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
      MenuInflater inflater = getMenuInflater();
      inflater.inflate(R.menu.menu, menu);
    
      MenuItem searchItem = menu.findItem(R.id.action_search);
      SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
      if (searchView != null) {
         searchView.setOnQueryTextListener(this);
      }
    
      return super.onCreateOptionsMenu(menu);
    }
Mohsen Afshin
fuente
3
Si esto resolvió su problema, probablemente debería aceptar su respuesta. También me gustaría señalar a todas las otras personas con problemas similares a un hilo más que discute problemas similares: stackoverflow.com/q/18407171/1108032 . Si el hilo actual no resuelve sus problemas, considere buscar las soluciones allí.
Boris Strandjev
44
¡Gran respuesta! Podría ser útil aclarar también que la "aplicación" en la aplicación: actionViewClass también requiere una declaración xmlns adicional para el espacio de nombres "aplicación".
jklp
3
Es necesario decir que la android.support.v7.widget.SearchViewclase no debe confundirse con la clase 'android.support.v4.widget.SearchViewCompat' (que se conoce como un error común al usar la biblioteca ActionBarCompat)
Alex Semeniuk
1
@jklp Intento agregar una declaración xmlns <menu xmlns:app="http://schemas.android.com/apk/res/android" >pero obtengo un error Attribute is missing the Android namespace prefix. ¿Lo entiendes y cómo lo arreglas?
anticafe
55
También tenga en cuenta que android: showAsAction también debe cambiarse a app: showAsAction también. También asegúrese de que su tema para la actividad (no solo la aplicación) haga referencia a un tema de appcompat. Lo último, la declaración de la aplicación es " schemas.android.com/apk/res-auto "
Kalel Wade
85

En mi caso fue el archivo ProGuard. Necesita agregar esta línea:

-keep class android.support.v7.widget.SearchView { *; }
Ivan Vazhnov
fuente
2
Wow, ¿por qué es esto una cosa? Esto fue lo único que funcionó para mí.
Claud
2
+1. Es bastante obvio, pero aún lo mencionaré: en caso de que haya extendido SearchView a otra clase, ¡mantenga la ruta a esa clase en guardia!
user2520215
42

Para mí, una menu.xmlimportación incorrecta de espacio de nombres causó este problema.

Mi original menu.xml:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/tools">
        <item android:id="@+id/action_search"
              android:title="@string/map_option_search"
              android:icon="@drawable/ic_action_search"
              app:showAsAction="collapseActionView|ifRoom"
              app:actionViewClass="android.support.v7.widget.SearchView"/>
</menu>

Parece que xmlns:app="http://schemas.android.com/tools"estaba causando el MenuItemCompat.getActionView()regreso null. Cambiar esta importación para xmlns:app="http://schemas.android.com/apk/res-auto"solucionar el problema.

Nuevo trabajo menu.xml:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">
       <item android:id="@+id/action_search"
              android:title="@string/map_option_search"
              android:icon="@drawable/ic_action_search"
              app:showAsAction="collapseActionView|ifRoom"
              app:actionViewClass="android.support.v7.widget.SearchView"/>
</menu>
Sean Barbeau
fuente
5

Creo que el problema es que usas SearchView desde el paquete Support V7 y quizás tu nivel de API esté configurado en ..... 22 ??.

Cambiando el código a lo siguiente para solucionar el problema:

menu.xml

<?xml version="1.0" encoding="UTF-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item 
        android:id="@+id/action_search"
        android:icon="@drawable/actionbar_button_search"
        android:title="Search"
        android:showAsAction="always"
        android:actionViewClass="android.widget.SearchView" />
</menu> 
Michele Caggiano
fuente
1
¿Podría explicar por qué la muestra de código que proporcionó resuelve el problema? (Supongo que sí.)
Edgar N
4

Estaba con el mismo error, mi método getActionView()siempre volvía nulo. Entonces, hice las siguientes cosas:

<item android:id="@+id/action_search"
      android:icon="@drawable/abc_ic_search"
      android:title="@string/search_title"
      android:showAsAction="always"
      android:actionViewClass="android.widget.SearchView"/>

Vi en algunas publicaciones que la gente está usando la aplicación: o yourapp, pero la he usado normalmente android:ActionVewClass.

En mi onCreateOptionsMenumétodo:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.feed, menu);

    // Associate searchable configuration with the SearchView
    SearchManager searchManager = 
        (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    SearchView searchView = (SearchView) menu.findItem(R.id.action_search)
            .getActionView();
    searchView.setSearchableInfo(searchManager
            .getSearchableInfo(getComponentName()));

    return true;
}

Y no olvides poner en el onCreatemétodo:

// enabling action bar app icon and behaving it as toggle button
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);

Esto funciona muy bien para mi actividad "extendiéndose" para FragmentActivityy ActionBarActivity.

Franzé Jr.
fuente
2

La respuesta anterior de Mohsen Afshin fue mi punto de partida e hice algunos ajustes para que funcione con mi configuración:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu, menu);
    MenuItem searchItem = menu.findItem(R.id.action_search);
    // SearchView searchView = (SearchView) MenuItemCompat
    //    .getActionView(searchItem);
    SearchView searchView = (SearchView) searchItem.getActionView();
    if (searchView != null) {
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String s) {
                // do something with s, the entered string
                query = s;
                Toast.makeText(getApplicationContext(), 
                    "String entered is " + s, Toast.LENGTH_SHORT).show();
                return true;
            }
            @Override
            public boolean onQueryTextChange(String s) {
                return false;
            }
        });
    }
    return super.onCreateOptionsMenu(menu);
}

menu.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity" >

<item android:id="@+id/action_search"
    android:orderInCategory="5"
    android:title="Search"
    android:icon="@drawable/ic_action_search"
    android:showAsAction="ifRoom|collapseActionView"
    android:actionViewClass="android.widget.SearchView" />
</menu>
kasiahayden
fuente
1

Tenía el mismo código, pero en lugar de usar la importación android.support.v7.widget.SearchView;que estaba usando import android.widget.SearchView;. Esto solucionó mi problema con el nullvalor. Tan solo cambie este código en su actividad de búsqueda y funcionará y también cambiará el espacio de nombres en el archivo xml.

marcelocolombo
fuente
Este era nuestro problema, teníamos una combinación de android.widget.SearchView en la Actividad, pero teníamos un uso parcial de v7 en nuestro archivo menu_main.xml. Solo asegúrese de que el archivo .xml también esté usando la aplicación: actionViewClass = "android.support.v7.widget.SearchView" también.
gmcc051
0

Aquí hay un fragmento de cómo manejar searchView desde la biblioteca de soporte v7:

@Override
public void onCreateOptionsMenu(final Menu menu,final MenuInflater inflater)
  {
  menu.clear();
  getActivity().getMenuInflater().inflate(...,menu);
  _searchView=(SearchView)MenuItemCompat.getActionView(_searchMenuItem);
  _searchView.setQueryHint(...);

  if(VERSION.SDK_INT<VERSION_CODES.HONEYCOMB)
    {
    final EditText searchTextView=(EditText)searchView.findViewById(R.id.search_src_text);
    if(searchTextView!=null)
      {
      searchTextView.setScroller(new Scroller(_context));
      searchTextView.setMaxLines(1);
      searchTextView.setVerticalScrollBarEnabled(true);
      searchTextView.setMovementMethod(new ScrollingMovementMethod());
      searchTextView.setTextColor(_context.getResources().getColor(App.getResIdFromAttribute(_context,android.R.attr.textColorPrimary)));
      }
    }
  _searchView.setOnQueryTextListener(new android.support.v7.widget.SearchView.OnQueryTextListener()
    {
    ...
    });
  MenuItemCompat.setActionView(_searchMenuItem,_searchView);
  MenuItemCompat.setOnActionExpandListener(_searchMenuItem,new OnActionExpandListener()
    {
    ...
    });
  super.onCreateOptionsMenu(menu,inflater);
  }


public static int getResIdFromAttribute(final Activity activity,final int attr)
  {
  if(attr==0)
    return 0;
  final TypedValue typedvalueattr=new TypedValue();
  activity.getTheme().resolveAttribute(attr,typedvalueattr,true);
  return typedvalueattr.resourceId;
  }

Además, si usa Proguard, agregue esto a su configuración:

-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class android.support.v7.widget.SearchView { *; }
-keepattributes *Annotation*
desarrollador de Android
fuente
Para quien quiera formatear el código, este es un formato muy conocido llamado "WhiteSmith". Cambiar a otro formato no lo mejora, ya que es cuestión de gustos.
Desarrollador de Android
@JJD Sí. Correcto. No es tan común como otros, pero lo he usado durante mucho tiempo. Puede configurarlo en Eclipse si lo desea.
Desarrollador de Android
Gracias por compartir. Me quedo con el valor predeterminado, ya que evita muchas discusiones no deseadas con miembros del equipo o colaboradores.
JJD
@JJD Eso también es cierto. En la oficina trabajamos con un estilo un poco diferente al predeterminado. De todos modos, un buen desarrollador debería ser capaz de manejar todos los estilos de formato comunes, y si "lastima los ojos", siempre puede copiar el código y formatearlo en varias herramientas de formato (en línea o en el IDE).
Desarrollador de Android
0

Tuve un problema muy similar con la diferencia de que estaba tratando de usar una clase que se extendió android.widget.ImageView

Si está utilizando ProGuard, debe especificar para permitir los métodos involucrados en esta clase.

-keep public class * extends android.widget.ImageView{
  public <init>(android.content.Context);
  public <init>(android.content.Context, android.util.AttributeSet);
  public <init>(android.content.Context, android.util.AttributeSet, int);
  public void set*(...);
}

http://proguard.sourceforge.net/manual/examples.html

Esto dice: "Permita todos los constructores necesarios que se puedan llamar desde xml y permita también cualquier configurador personalizado que use (agregue más según sea necesario)"

ElliotM
fuente
0

Lo hice por manual establecido en código Java:

<menu xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/user_info"
        android:title="@string/user_name_title"
        app:actionLayout="@layout/menu_item_username"
        android:showAsAction="always" />
</menu>

Archivo de diseño:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/usr_name_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginEnd="10dp"
        android:contentDescription="@string/user_info_image_des"
        android:padding="5dp"
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        android:text="@string/user_name_title"
        android:textStyle="bold"
        android:visibility="visible" />
</LinearLayout>

Luego en código java:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.connect_menu, menu);
        // show user name on the top of menu
        Log.e("menu", "Size: " + menu.size());
        MenuItem item = menu.getItem(0);
        item.setActionView(R.layout.menu_item_username);
        View v = item.getActionView();
        if (null == v) {
            Log.e("NULL POINTER EX", "NULL MENU VIEW");
        } else {
            TextView usrNameTitle = v.findViewById(R.id.usr_name_title);
            if (null != usrName && usrName.length() > 0) {
                usrNameTitle.setText(usrName);
            }
        }
        return true;
    }

ingrese la descripción de la imagen aquí

nobjta_9x_tq
fuente
-1

Eliminar código: clase pública DemoActivity extiende ActionBarActivity

Reemplazar por: clase pública DemoActivity extiende actividad

Hieu
fuente
2
¿Por qué debería hacerlo él? Por favor explique su respuesta un poco más en detalle.
Robin Ellerkmann
Cuando extiendo ActionBarActivity, siempre devuelve nulo. Pero solo extiendo la actividad, funciona normalmente
Hieu
Debe usar su propio espacio de nombres cuando use ActionBarActivity ya que es parte de la biblioteca de soporte. Como estás usando android: showAsAction en tu xml, funciona con Activity (que no es de la biblioteca de soporte) y no funciona con ActionBarActivity
Dennis K