MenuItemCompat.getActionView restituisce sempre null


142

Ho appena implementato la v7 AppCompatlibreria di supporto ma MenuItemCompat.getActionViewrestituisco sempre null in ogni versione di Android che ho provato (4.2.2, 2.3.4 ....)

Il SearchViewviene visualizzato nella barra delle azioni, ma non risponde a toccare le azioni e non si espande per mostrare la sua EditTexted è proprio come una semplice icona.

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

Risposte:


296

Finalmente ho trovato la soluzione.

  1. Modifica dello spazio dei nomi di actionViewClassda android:actionViewClassaapp:actionViewClass

  2. Implementazione android.support.v7.widget.SearchView.OnQueryTextListenerdell'interfaccia per l'attività corrente.

  3. Utilizzare direttamente setOnQueryTextListeneranzichéSearchViewCompat.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);
    }

3
Se questo ha risolto il tuo problema, probabilmente dovresti accettare la tua risposta. Vorrei anche indicare tutte le altre persone con problemi simili a un altro thread che discute problemi simili: stackoverflow.com/q/18407171/1108032 . Se il thread corrente non risolve i tuoi problemi, considera di cercare le soluzioni lì.
Boris Strandjev,

4
Bella risposta! Potrebbe anche essere utile chiarire che l '"app" nell'app: actionViewClass richiede anche un'ulteriore dichiarazione xmlns per lo spazio dei nomi "app".
jklp,

3
Devo dire che la android.support.v7.widget.SearchViewclasse non deve essere confusa con la classe "android.support.v4.widget.SearchViewCompat" (che è noto come errore comune quando si utilizza la libreria ActionBarCompat)
Alex Semeniuk,

1
@jklp Provo ad aggiungere la dichiarazione xmlns <menu xmlns:app="http://schemas.android.com/apk/res/android" >ma ottengo un errore Attribute is missing the Android namespace prefix. Lo capisci e come lo ripari?
anticafe,

5
Inoltre, android: showAsAction deve essere modificato in app: showAsAction. Assicurati anche che il tuo tema per l'attività (non solo l'applicazione) faccia riferimento a un tema di appcompat. L'ultima cosa, la dichiarazione dell'app è " schemas.android.com/apk/res-auto "
Kalel Wade

85

Nel mio caso era il file ProGuard. Devi aggiungere questa riga:

-keep class android.support.v7.widget.SearchView { *; }

2
Wow, perché è una cosa del genere? Questa è stata l'unica cosa che ha funzionato per me.
Claud,

2
+1. Abbastanza ovvio, ma citerò comunque: nel caso in cui tu abbia esteso SearchView ad un'altra classe, mantieni il percorso di quella classe in proguard!
user2520215

42

Per me, menu.xmlun'importazione errata dello spazio dei nomi ha causato questo problema.

Il mio originale 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>

Sembra che il xmlns:app="http://schemas.android.com/tools"motivo stia causando il MenuItemCompat.getActionView()ritorno null. La modifica di questa importazione per xmlns:app="http://schemas.android.com/apk/res-auto"risolvere il problema.

Nuovo lavoro 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>

5

Penso che il problema sia che usi SearchView dal pacchetto Support V7 e forse il tuo livello API è impostato su ..... 22 ??.

Modifica del codice in quanto segue per risolvere il 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> 

1
Potresti spiegare perché l'esempio di codice che hai fornito risolve il problema? (Suppongo che lo sia.)
Edgar N,

4

Ero con lo stesso errore, il mio metodo getActionView()restituiva sempre null. Quindi, ho fatto le seguenti cose:

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

Ho visto in alcuni post che le persone usano app: o yourapp, ma l'ho usato normalmente android:ActionVewClass.

Sul mio onCreateOptionsMenumetodo:

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

E non dimenticare di inserire il onCreatemetodo:

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

Questo funziona molto bene per la mia attività di "estensione" per FragmentActivitye ActionBarActivity.


2

La risposta di Mohsen Afshin sopra è stata il mio punto di partenza e ho apportato alcune modifiche per farlo funzionare con la mia configurazione:

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

1

Avevo lo stesso codice, ma invece di usare l'importazione android.support.v7.widget.SearchView;che stavo usando import android.widget.SearchView;. Ciò ha risolto il mio problema con il nullvalore. Quindi cambia questo codice nella tua attività di ricerca e funzionerà e cambierà anche lo spazio dei nomi nel file xml.


Questo era il nostro problema, avevamo un mix di android.widget.SearchView nell'attività ma avevamo un uso parziale di v7 nel nostro file menu_main.xml. Assicurati solo che il file .xml utilizzi anche app: actionViewClass = "android.support.v7.widget.SearchView".
gmcc051,

0

Ecco uno snippet su come gestire searchView dalla libreria di supporto 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;
  }

Inoltre, se si utilizza Proguard, aggiungerlo alla sua configurazione:

-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class android.support.v7.widget.SearchView { *; }
-keepattributes *Annotation*

Per chiunque volesse formattare il codice, questa è una formattazione molto conosciuta chiamata "WhiteSmith". Il passaggio a un altro formato non lo rende migliore, poiché è una questione di gusti.
sviluppatore Android il

@JJD Sì. Corretta. Non è così comune come gli altri, ma l'ho usato per molto tempo. Se lo desideri, puoi impostarlo su Eclipse.
sviluppatore Android il

Grazie per la condivisione. Rimango con il default poiché evita molte discussioni indesiderate con membri del team o collaboratori.
JJD,

@JJD Questo è anche vero. in ufficio lavoriamo con uno stile un po 'diverso da quello predefinito. Ad ogni modo, un buon sviluppatore dovrebbe essere in grado di gestire tutti gli stili di formattazione comuni e se "fa male agli occhi" puoi sempre copiare il codice e formattarlo su vari strumenti di formattazione (online o sull'IDE).
sviluppatore Android il

0

Ho avuto un problema molto simile con la differenza che stavo tentando di utilizzare una classe estesa android.widget.ImageView

Se si utilizza ProGuard, è necessario specificare per consentire i metodi coinvolti in questa 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

Questo dice "Consenti a tutti i costruttori necessari che potrebbero essere chiamati da XML e consenti anche a qualsiasi setter personalizzato che utilizza (aggiungi altro se necessario)"


0

L'ho fatto con il manuale impostato nel codice 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>

File di layout:

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

Quindi nel codice 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;
    }

inserisci qui la descrizione dell'immagine


-1

Rimuovi codice: DemoActivity di classe pubblica estende ActionBarActivity

Sostituisci con: la classe pubblica DemoActivity estende l' attività


2
Perché dovrebbe farlo? Spiega la tua risposta un po 'più in dettaglio.
Robin Ellerkmann,

Quando estendo ActionBarActivity, restituisce sempre null. Ma estendo solo l'attività, funziona normalmente
Hieu,

È necessario utilizzare il proprio spazio dei nomi quando si utilizza ActionBarActivity in quanto fa parte della libreria di supporto. Dal momento che stai usando Android: showAsAction nel tuo XML funziona con Activity (che non proviene dalla libreria di supporto) e non funziona con ActionBarActivity
Dennis K
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.