142

I just implemented the v7 AppCompat support library but the MenuItemCompat.getActionView always return null in every Android version I tested (4.2.2, 2.3.4 ....)

The SearchView is displayed in action bar but it doesn't respond to touch actions and doesn't expand to show its EditText and is just like a simple icon.

@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>
JJD
  • 50,076
  • 60
  • 203
  • 339
Mohsen Afshin
  • 13,273
  • 10
  • 65
  • 90

11 Answers11

296

Finally I found the solution.

  1. Changing namespace of actionViewClass from android:actionViewClass to app:actionViewClass

  2. Implementing android.support.v7.widget.SearchView.OnQueryTextListener interface for current activity.

  3. Directly use setOnQueryTextListener instead of 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);
    }
    
Mohsen Afshin
  • 13,273
  • 10
  • 65
  • 90
  • 3
    If this solved your problem you should probably accept your answer. I would also like to point all the other people with similar problems to one more thread discussing similar issues: http://stackoverflow.com/q/18407171/1108032. If the current thread does not solve your problems, consider looking into the solutions there. – Boris Strandjev Sep 01 '13 at 11:40
  • 4
    Great answer! It might pay to clarify too that the "app" in app:actionViewClass also requires an additional xmlns declaration for the "app" namespace. – jklp Oct 31 '13 at 01:35
  • 3
    Need to say that `android.support.v7.widget.SearchView` class should not be confused with 'android.support.v4.widget.SearchViewCompat' class (which is known as a common mistake when using ActionBarCompat library) – Alex Semeniuk Nov 11 '13 at 09:38
  • Your namespace hint solved my issue :) This was the missing puzzle piece. – EinLama Nov 19 '13 at 10:22
  • 1
    @jklp I try to add xmlns declaration `` but get error `Attribute is missing the Android namespace prefix`. Do you get it, and how do you fix it? – anticafe Feb 11 '14 at 15:30
  • 5
    Also note, android:showAsAction needs to be changed to app:showAsAction as well. Also make sure your theme for the activity (not just the application) is referencing an appcompat theme. Last thing, the app declartion is "http://schemas.android.com/apk/res-auto" – Kalel Wade Mar 05 '14 at 17:23
  • Actually point number 1 did the trick! Such a standard error, dammit, but I just didn't see it. Thanks so much, life saver! – Irina Anastasiu May 14 '14 at 11:03
  • 1
    My issue was Proguard. If you have Proguard enabled, make sure you have a rule that keeps the `android.support.v7.widget.SearchView`. For example, to keep everything in all the different versions of the support library, add `-keep class android.support.** { *; }` and `-keep interface android.support.** { *; }`. – ashughes May 24 '14 at 00:16
  • Thanks guy, your response helps me a lot... Probably you have to add one point app:actionViewClass="android.support.v7.widget.SearchView" – emaleavil Aug 05 '15 at 19:40
  • 1. Changing namespace of actionViewClass from android:actionViewClass to app:actionViewClass works for me, thanks! – Ivan Dokov Jul 12 '17 at 08:40
  • Extra comment for the visitors: If still the above have not worked for you, delete the application from your device/emulator, and run the following gradle tasks (clean, build) and then deploy (possibly using assembleDebug) – George Daramouskas Jan 03 '18 at 17:35
84

In my case it was ProGuard file. You need to add this line:

-keep class android.support.v7.widget.SearchView { *; }
JJD
  • 50,076
  • 60
  • 203
  • 339
Ivan Vazhnov
  • 1,291
  • 11
  • 9
  • 2
    Wow, why is this a thing? This was the only thing that worked for me. – Claud Nov 30 '15 at 22:11
  • 2
    +1. Pretty obvious, but I'll still mention - In case you have extended the SearchView to another class, keep the path to that class in proguard! – user2520215 Apr 05 '16 at 14:29
42

For me, an incorrect menu.xml namespace import caused this problem.

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

It looks like the xmlns:app="http://schemas.android.com/tools" was causing MenuItemCompat.getActionView() to return null. Changing this import to xmlns:app="http://schemas.android.com/apk/res-auto" fixed the problem.

New working 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
  • 11,496
  • 8
  • 58
  • 111
5

I think that the problem is that you use the SearchView from the Support V7 package and maybe your API level is set to.....22??.

Changing your code to the following in order to fix the problem:

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

I was with the same error, my method getActionView() was always returning null. So, I've made the following things:

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

I saw in some posts that the people are using app: or yourapp, but i've used normally android:ActionVewClass.

On my onCreateOptionsMenu method:

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

And do not forget to put in the onCreate method:

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

This works very well for my activity "extending" for FragmentActivity and ActionBarActivity.

JJD
  • 50,076
  • 60
  • 203
  • 339
Franzé Jr.
  • 1,194
  • 13
  • 20
2

Mohsen Afshin's answer above was my starting point and I made some tweaks to get it working with my setup:

@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>
JJD
  • 50,076
  • 60
  • 203
  • 339
2

I did this by manual set in java code:

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

Layout file:

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

Then in 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;
    }

enter image description here

nobjta_9x_tq
  • 1,205
  • 14
  • 16
1

I had the same code, but instead of using the import android.support.v7.widget.SearchView; I was using import android.widget.SearchView; . This fixed my problem with the null value. So just change this code in your search activity and it will work and also change the namespace in xml file.

  • This was our issue, we had a mix of android.widget.SearchView in the Activity but had a partial use of v7 in our menu_main.xml file. Just make sure the .xml file is also using app:actionViewClass="android.support.v7.widget.SearchView" too. – gmcc051 Jun 18 '17 at 03:24
0

Here's a snippet of how to handle the searchView from 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;
  }

Also, if you use Proguard, add this to its configuration :

-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class android.support.v7.widget.SearchView { *; }
-keepattributes *Annotation*
android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • To whoever wanted to format the code, this is a very known formatting called "WhiteSmith". Changing to another format doesn't make it better, as this is a matter of taste. – android developer Nov 27 '14 at 13:45
  • @JJD Yes. Correct. It's not as common as others, but I've used it for a very long time. You can set it on Eclipse if you wish. – android developer Nov 27 '14 at 13:53
  • Thanks for sharing. I stay with the default since it avoids a lot unwanted discussions with team members or contributors. – JJD Nov 27 '14 at 14:41
  • @JJD That's also true. at the office we work with a bit different style than the default one. Anyway, a good developer should be able to handle all of the common formatting styles, and if it "hurts the eyes" you can always copy the code and format it on various formatting tools (online, or on the IDE). – android developer Nov 27 '14 at 14:50
0

I had a very similar issue with the difference being I was attempting to use a class that extended android.widget.ImageView

If you're using ProGuard, you need to specify to allow the methods involved in this class.

-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

This says, "Allow all needed constructors that might be called from xml and allow any custom setters it uses as well (add more as needed)"

woliveirajr
  • 9,433
  • 1
  • 39
  • 49
em_
  • 2,134
  • 2
  • 24
  • 39
-1

Remove code: public class DemoActivity extends ActionBarActivity

Replace by: public class DemoActivity extends Activity

Hieu
  • 11
  • 2
    Why should he do so? Please explain your answer a bit more in detail. – Robin Ellerkmann Jan 23 '15 at 16:55
  • When I extends ActionBarActivity, it alway return null. But I extends Activity only, it work normal – Hieu Jan 23 '15 at 19:07
  • You need to use your own namespace when using ActionBarActivity as it is a part of support library. Since you're using android:showAsAction in your xml it works with Activity (which is not from support library) and doesn't work with ActionBarActivity – Dennis K Apr 20 '15 at 18:44