MenuItemCompat.getActionView renvoie toujours null

142

Je viens d'implémenter la v7 AppCompatbibliothèque de support mais le MenuItemCompat.getActionViewretourne toujours null dans chaque version d'Android que j'ai testée (4.2.2, 2.3.4 ....)

Le SearchViewest affiché dans la barre d'actions mais il ne répond pas aux actions tactiles et ne se développe pas pour l'afficher EditTextet ressemble à une simple icône.

@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
la source

Réponses:

296

Enfin j'ai trouvé la solution.

  1. Modification de l' espace de noms actionViewClassde android:actionViewClasslaapp:actionViewClass

  2. Implémentation de l' android.support.v7.widget.SearchView.OnQueryTextListenerinterface pour l'activité actuelle.

  3. Utiliser directement setOnQueryTextListenerau lieu 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
la source
3
Si cela a résolu votre problème, vous devriez probablement accepter votre réponse. Je voudrais également pointer toutes les autres personnes ayant des problèmes similaires vers un autre fil de discussion traitant de problèmes similaires: stackoverflow.com/q/18407171/1108032 . Si le thread actuel ne résout pas vos problèmes, envisagez d'y rechercher les solutions.
Boris Strandjev
4
Très bonne réponse! Il pourrait être utile de préciser également que "app" dans app: actionViewClass nécessite également une déclaration xmlns supplémentaire pour l'espace de noms "app".
jklp
3
Il faut dire que la android.support.v7.widget.SearchViewclasse ne doit pas être confondue avec la classe 'android.support.v4.widget.SearchViewCompat' (qui est connue comme une erreur courante lors de l'utilisation de la bibliothèque ActionBarCompat)
Alex Semeniuk
1
@jklp J'essaye d'ajouter une déclaration xmlns <menu xmlns:app="http://schemas.android.com/apk/res/android" >mais j'obtiens une erreur Attribute is missing the Android namespace prefix. Comprenez-vous et comment y remédier?
anticafe
5
Notez également que android: showAsAction doit également être remplacé par app: showAsAction. Assurez-vous également que votre thème pour l'activité (et pas seulement l'application) fait référence à un thème appcompat. Dernière chose, la déclinaison de l'application est " schemas.android.com/apk/res-auto "
Kalel Wade
85

Dans mon cas, c'était le fichier ProGuard. Vous devez ajouter cette ligne:

-keep class android.support.v7.widget.SearchView { *; }
Ivan Vazhnov
la source
2
Wow, pourquoi est-ce une chose? C'était la seule chose qui fonctionnait pour moi.
Claud
2
+1. Assez évident, mais je vais quand même mentionner - Au cas où vous auriez étendu le SearchView à une autre classe, gardez le chemin vers cette classe dans proguard!
user2520215
42

Pour moi, une erreur menu.xml importation d'espace de noms causé ce problème.

Mon 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>

On dirait que le xmlns:app="http://schemas.android.com/tools"faisait MenuItemCompat.getActionView()revenir null. Changer cette importation enxmlns:app="http://schemas.android.com/apk/res-auto" résoudre le problème.

Nouveau travail 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
la source
5

Je pense que le problème est que vous utilisez le SearchView du package Support V7 et que votre niveau d'API est peut-être défini sur ..... 22 ??.

Changez votre code comme suit afin de résoudre le problème:

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
la source
1
Pouvez-vous expliquer pourquoi l'exemple de code que vous avez fourni résout le problème? (Je suppose que c'est le cas.)
Edgar N
4

J'étais avec la même erreur, ma méthode getActionView()retournait toujours null. Donc, j'ai fait les choses suivantes:

<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"/>

J'ai vu dans certains articles que les gens utilisent app: ou yourapp, mais je l'ai utilisé normalement android:ActionVewClass.

Sur ma onCreateOptionsMenuméthode:

@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;
}

Et n'oubliez pas de mettre dans la onCreateméthode:

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

Cela fonctionne très bien pour mon activité "extension" pour FragmentActivityet ActionBarActivity.

Franzé Jr.
la source
2

La réponse de Mohsen Afshin ci-dessus était mon point de départ et j'ai fait quelques ajustements pour le faire fonctionner avec ma configuration:

@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
la source
1

J'avais le même code, mais au lieu d'utiliser l'importation que android.support.v7.widget.SearchView;j'utilisais import android.widget.SearchView;. Cela a résolu mon problème avec la nullvaleur. Alors changez simplement ce code dans votre activité de recherche et cela fonctionnera et changera également l'espace de noms dans le fichier xml.

marcelocolombo
la source
C'était notre problème, nous avions un mélange de android.widget.SearchView dans l'activité mais avions une utilisation partielle de la v7 dans notre fichier menu_main.xml. Assurez-vous simplement que le fichier .xml utilise également l'application: actionViewClass = "android.support.v7.widget.SearchView".
gmcc051
0

Voici un extrait de la façon de gérer le searchView à partir de la bibliothèque de support 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;
  }

De plus, si vous utilisez Proguard, ajoutez ceci à sa configuration:

-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class android.support.v7.widget.SearchView { *; }
-keepattributes *Annotation*
développeur android
la source
Pour qui veut formater le code, il s'agit d'un formatage très connu appelé "WhiteSmith". Passer à un autre format ne l'améliore pas, car c'est une question de goût.
développeur android
@JJD Oui. Correct. Ce n'est pas aussi courant que d'autres, mais je l'utilise depuis très longtemps. Vous pouvez le configurer sur Eclipse si vous le souhaitez.
développeur android
Merci d'avoir partagé. Je reste avec la valeur par défaut car cela évite beaucoup de discussions indésirables avec les membres de l'équipe ou les contributeurs.
JJD
@JJD C'est également vrai. au bureau, nous travaillons avec un style un peu différent de celui par défaut. Quoi qu'il en soit, un bon développeur devrait être capable de gérer tous les styles de formatage courants, et si cela «fait mal aux yeux», vous pouvez toujours copier le code et le formater sur divers outils de formatage (en ligne ou sur l'EDI).
développeur android
0

J'ai eu un problème très similaire, la différence étant que j'essayais d'utiliser une classe qui s'étendait android.widget.ImageView

Si vous utilisez ProGuard, vous devez spécifier d'autoriser les méthodes impliquées dans cette classe.

-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

Cela dit: "Autoriser tous les constructeurs nécessaires qui pourraient être appelés à partir de xml et autoriser tous les setters personnalisés qu'il utilise également (ajoutez-en plus si nécessaire)"

ElliotM
la source
0

Je l'ai fait par le manuel défini dans le code 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>

Fichier de mise en page:

<?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>

Puis en code 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;
    }

entrez la description de l'image ici

nobjta_9x_tq
la source
-1

Supprimer le code: la classe publique DemoActivity étend ActionBarActivity

Remplacer par: la classe publique DemoActivity étend l' activité

Hieu
la source
2
Pourquoi le ferait-il? Veuillez expliquer votre réponse un peu plus en détail.
Robin Ellerkmann
Lorsque j'étend ActionBarActivity, il renvoie toujours null. Mais je ne prolonge que l'activité, cela fonctionne normalement
Hieu
Vous devez utiliser votre propre espace de noms lorsque vous utilisez ActionBarActivity car il fait partie de la bibliothèque de support. Puisque vous utilisez Android: showAsAction dans votre xml, il fonctionne avec Activity (qui ne provient pas de la bibliothèque de support) et ne fonctionne pas avec ActionBarActivity
Dennis K