MenuItemCompat.getActionView gibt immer null zurück

142

Ich habe gerade die v7 AppCompatSupport-Bibliothek implementiert, aber dieMenuItemCompat.getActionView in jeder von mir getesteten Android-Version (4.2.2, 2.3.4 ....) wird immer null zurückgegeben.

Das SearchViewwird in der Aktionsleiste angezeigt, reagiert jedoch nicht auf Berührungsaktionen und wird nicht erweitert, um es anzuzeigenEditText ist wie ein einfaches Symbol.

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

Antworten:

296

Endlich habe ich die Lösung gefunden.

  1. Ändern des Namespace von actionViewClassvon android:actionViewClassnachapp:actionViewClass

  2. Implementierungsschnittstelle android.support.v7.widget.SearchView.OnQueryTextListenerfür aktuelle Aktivität.

  3. Direkt verwenden setOnQueryTextListenerstattSearchViewCompat.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
quelle
3
Wenn dies Ihr Problem gelöst hat, sollten Sie wahrscheinlich Ihre Antwort akzeptieren. Ich möchte auch alle anderen Personen mit ähnlichen Problemen auf einen weiteren Thread verweisen, in dem ähnliche Probleme diskutiert werden: stackoverflow.com/q/18407171/1108032 . Wenn der aktuelle Thread Ihre Probleme nicht löst, sollten Sie die dortigen Lösungen prüfen.
Boris Strandjev
4
Gute Antwort! Es kann sich auch lohnen, zu verdeutlichen, dass für die "App" in app: actionViewClass auch eine zusätzliche xmlns-Deklaration für den Namespace "app" erforderlich ist.
jklp
3
android.support.v7.widget.SearchViewIch muss sagen, dass die Klasse nicht mit der Klasse 'android.support.v4.widget.SearchViewCompat' verwechselt werden sollte (was als häufiger Fehler bei der Verwendung der ActionBarCompat-Bibliothek bekannt ist)
Alex Semeniuk
1
@jklp Ich versuche, eine xmlns-Deklaration hinzuzufügen <menu xmlns:app="http://schemas.android.com/apk/res/android" >, erhalte aber eine Fehlermeldung Attribute is missing the Android namespace prefix. Bekommst du es und wie reparierst du es?
Anticafe
5
Beachten Sie auch, dass android: showAsAction ebenfalls in app: showAsAction geändert werden muss. Stellen Sie außerdem sicher, dass Ihr Thema für die Aktivität (nicht nur die Anwendung) auf ein Appcompat-Thema verweist. Als letztes ist die App-Deklaration " schemas.android.com/apk/res-auto "
Kalel Wade
85

In meinem Fall war es eine ProGuard-Datei. Sie müssen diese Zeile hinzufügen:

-keep class android.support.v7.widget.SearchView { *; }
Ivan Vazhnov
quelle
2
Wow, warum ist das so? Dies war das einzige, was für mich funktioniert hat.
Claud
2
+1. Ziemlich offensichtlich, aber ich werde trotzdem erwähnen - Falls Sie die SearchView auf eine andere Klasse erweitert haben, behalten Sie den Pfad zu dieser Klasse in Proguard!
user2520215
42

Für mich hat ein falscher menu.xmlNamespace-Import dieses Problem verursacht.

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

Es sieht xmlns:app="http://schemas.android.com/tools"so aus MenuItemCompat.getActionView(), als würde der zurückkehren null. Durch Ändern dieses Imports wurde xmlns:app="http://schemas.android.com/apk/res-auto"das Problem behoben.

Neue Arbeitsweise 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
quelle
5

Ich denke, dass das Problem darin besteht, dass Sie SearchView aus dem Support V7-Paket verwenden und möglicherweise Ihre API-Ebene auf ..... 22 ?? eingestellt ist.

Ändern Sie Ihren Code wie folgt, um das Problem zu beheben:

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
quelle
1
Können Sie erklären, warum das von Ihnen bereitgestellte Codebeispiel das Problem löst? (Ich nehme an, dass es tut.)
Edgar N
4

Ich hatte den gleichen Fehler, meine Methode getActionView()gab immer null zurück. Also habe ich folgende Dinge gemacht:

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

Ich habe in einigen Posts gesehen, dass die Leute App verwenden: oder yourapp, aber ich habe normal verwendet android:ActionVewClass .

Zu meiner onCreateOptionsMenuMethode:

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

Und vergessen Sie nicht, die onCreateMethode einzugeben:

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

Dies funktioniert sehr gut für meine Aktivität "Erweitern" für FragmentActivityund ActionBarActivity.

Franzé Jr.
quelle
2

Die Antwort von Mohsen Afshin oben war mein Ausgangspunkt und ich habe einige Verbesserungen vorgenommen, damit es mit meinem Setup funktioniert:

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

Ich hatte den gleichen Code, aber anstatt den Import zu verwenden, den android.support.v7.widget.SearchView;ich verwendet habe import android.widget.SearchView;. Dies hat mein Problem mit dem nullWert behoben . Ändern Sie einfach diesen Code in Ihrer Suchaktivität und er funktioniert und ändert auch den Namespace in der XML-Datei.

marcelocolombo
quelle
Dies war unser Problem. Wir hatten eine Mischung aus android.widget.SearchView in der Aktivität, hatten jedoch eine teilweise Verwendung von v7 in unserer Datei menu_main.xml. Stellen Sie einfach sicher, dass die XML-Datei auch die App verwendet: actionViewClass = "android.support.v7.widget.SearchView".
gmcc051
0

Hier ist ein Ausschnitt aus der Handhabung von searchView aus der Support Library 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;
  }

Wenn Sie Proguard verwenden, fügen Sie dies zu seiner Konfiguration hinzu:

-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class android.support.v7.widget.SearchView { *; }
-keepattributes *Annotation*
Android-Entwickler
quelle
Für alle, die den Code formatieren möchten, ist dies eine sehr bekannte Formatierung namens "WhiteSmith". Ein Wechsel in ein anderes Format macht es nicht besser, da dies Geschmackssache ist.
Android-Entwickler
@JJD Ja. Richtig. Es ist nicht so häufig wie andere, aber ich habe es sehr lange benutzt. Sie können es auf Eclipse einstellen, wenn Sie möchten.
Android-Entwickler
Danke für das Teilen. Ich bleibe bei der Standardeinstellung, da dadurch viele unerwünschte Diskussionen mit Teammitgliedern oder Mitwirkenden vermieden werden.
JJD
@JJD Das stimmt auch. Im Büro arbeiten wir mit einem etwas anderen Stil als dem Standard. Auf jeden Fall sollte ein guter Entwickler in der Lage sein, alle gängigen Formatierungsstile zu verarbeiten. Wenn dies "die Augen verletzt", können Sie den Code jederzeit kopieren und mit verschiedenen Formatierungswerkzeugen (online oder in der IDE) formatieren.
Android-Entwickler
0

Ich hatte ein sehr ähnliches Problem mit dem Unterschied, dass ich versuchte, eine erweiterte Klasse zu verwenden android.widget.ImageView

Wenn Sie ProGuard verwenden, müssen Sie angeben, um die an dieser Klasse beteiligten Methoden zuzulassen.

-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

Dies besagt: "Erlaube allen benötigten Konstruktoren, die von XML aufgerufen werden könnten, und erlaube auch alle benutzerdefinierten Setter, die es verwendet (füge nach Bedarf weitere hinzu)."

ElliotM
quelle
0

Ich habe dies durch manuelles Einstellen in Java-Code getan:

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

Layoutdatei:

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

Dann im Java-Code:

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

Geben Sie hier die Bildbeschreibung ein

nobjta_9x_tq
quelle
-1

Entfernen Sie den Code ein : public class DemoActivity erstreckt ActionBarActivity

Ersetzen durch: public class DemoActivity erweitert Activity

Hieu
quelle
2
Warum sollte er das tun? Bitte erläutern Sie Ihre Antwort etwas ausführlicher.
Robin Ellerkmann
Wenn ich ActionBarActivity erweitere, wird immer null zurückgegeben. Aber ich erweitere nur Aktivität, es funktioniert normal
Hieu
Sie müssen Ihren eigenen Namespace verwenden, wenn Sie ActionBarActivity verwenden, da es Teil der Support-Bibliothek ist. Da Sie android: showAsAction in Ihrer XML verwenden, funktioniert es mit Activity (das nicht aus der Support-Bibliothek stammt) und nicht mit ActionBarActivity
Dennis K