【问题标题】:MenuItemCompat.getActionView always returns nullMenuItemCompat.getActionView 总是返回 null
【发布时间】:2018-10-23 08:53:30
【问题描述】:

我刚刚实现了 v7 AppCompat 支持库,但 MenuItemCompat.getActionView 在我测试的每个 Android 版本(4.2.2、2.3.4 ....)中总是返回 null

SearchView 显示在操作栏中,但它不会响应触摸操作,也不会展开以显示其EditText,就像一个简单的图标。

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

【问题讨论】:

    标签: android searchview android-actionbar-compat android-search


    【解决方案1】:

    我终于找到了解决办法。

    1. actionViewClass 的命名空间从 android:actionViewClass 更改为 app:actionViewClass

    2. 为当前活动实现android.support.v7.widget.SearchView.OnQueryTextListener 接口。

    3. 直接用setOnQueryTextListener代替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);
      }
      

    【讨论】:

    • 如果这解决了您的问题,您可能应该接受您的回答。我还想将所有其他有类似问题的人指向另一个讨论类似问题的线程:stackoverflow.com/q/18407171/1108032。如果当前线程不能解决您的问题,请考虑查看那里的解决方案。
    • 很好的答案!还需要澄清一下,app:actionViewClass 中的“app”还需要为“app”命名空间添加一个额外的 xmlns 声明。
    • 需要说android.support.v7.widget.SearchView类不应该与'android.support.v4.widget.SearchViewCompat'类混淆(这被称为使用ActionBarCompat库时的常见错误)
    • @jklp 我尝试添加 xmlns 声明 &lt;menu xmlns:app="http://schemas.android.com/apk/res/android" &gt; 但得到错误 Attribute is missing the Android namespace prefix。你明白了吗,你如何解决它?
    • 另请注意,android:showAsAction 也需要更改为 app:showAsAction。还要确保您的活动主题(不仅仅是应用程序)正在引用 appcompat 主题。最后一件事,应用声明是“schemas.android.com/apk/res-auto
    【解决方案2】:

    就我而言,它是 ProGuard 文件。你需要添加这一行:

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

    【讨论】:

    • 哇,这是为什么?这是唯一对我有用的东西。
    • +1。很明显,但我还是要提一下 - 如果您已将 SearchView 扩展到另一个类,请将该类的路径保留在 proguard 中!
    【解决方案3】:

    对我来说,不正确的 menu.xml 命名空间导入导致了这个问题。

    我原来的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>
    

    看起来xmlns:app="http://schemas.android.com/tools" 导致MenuItemCompat.getActionView() 返回null。将此导入更改为 xmlns:app="http://schemas.android.com/apk/res-auto" 解决了问题。

    新工作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>
    

    【讨论】:

      【解决方案4】:

      我认为问题在于您使用 Support V7 包中的 SearchView,并且您的 API 级别可能设置为.....22??。

      将您的代码更改为以下内容以解决问题:

      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> 
      

      【讨论】:

      • 您能解释一下为什么您提供的代码示例可以解决问题吗? (我认为确实如此。)
      【解决方案5】:

      我遇到了同样的错误,我的方法 getActionView() 总是返回 null。所以,我做了以下事情:

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

      我在一些帖子中看到人们正在使用 app: 或 yourapp,但我已经正常使用android:ActionVewClass

      关于我的onCreateOptionsMenu 方法:

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

      别忘了输入onCreate 方法:

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

      这非常适合我为FragmentActivityActionBarActivity“扩展”的活动。

      【讨论】:

        【解决方案6】:

        上面 Mohsen Afshin 的回答是我的出发点,我做了一些调整以使其与我的设置配合使用:

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

        【讨论】:

          【解决方案7】:

          我是在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>
          

          布局文件:

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

          然后在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;
              }
          

          【讨论】:

            【解决方案8】:

            我有相同的代码,但我没有使用导入 android.support.v7.widget.SearchView; 而是使用 import android.widget.SearchView; 。这解决了我对null 值的问题。 因此,只需在您的搜索活动中更改此代码,它就会起作用,并且还会更改 xml 文件中的命名空间。

            【讨论】:

            • 这是我们的问题,我们在 Activity 中混合使用了 android.widget.SearchView,但在 menu_main.xml 文件中部分使用了 v7。只要确保 .xml 文件也在使用 app:actionViewClass="android.support.v7.widget.SearchView" 。
            【解决方案9】:

            这是一个关于如何处理支持库 v7 中的 searchView 的 sn-p:

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

            另外,如果您使用 Proguard,请将其添加到其配置中:

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

            【讨论】:

            • 对于想要格式化代码的人来说,这是一种非常知名的格式,称为“WhiteSmith”。更改为另一种格式并不能让它变得更好,因为这是一个品味问题。
            • @JJD 是的。正确的。它不像其他人那样常见,但我已经使用了很长时间。如果你愿意,你可以在 Eclipse 上设置它。
            • 感谢分享。我保留默认设置,因为它避免了与团队成员或贡献者进行大量不必要的讨论。
            • @JJD 这也是真的。在办公室,我们的工作风格与默认风格略有不同。无论如何,一个优秀的开发人员应该能够处理所有常见的格式化样式,如果它“伤眼”,您可以随时复制代码并在各种格式化工具(在线或在 IDE)上格式化。
            【解决方案10】:

            我有一个非常相似的问题,不同之处在于我试图使用扩展 android.widget.ImageView 的类

            如果您使用 ProGuard,则需要指定允许此类中涉及的方法。

            -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

            这表示,“允许可能从 xml 调用的所有需要​​的构造函数,并允许它使用的任何自定义设置器(根据需要添加更多)”

            【讨论】:

              【解决方案11】:

              删除代码: 公共类 DemoActivity 扩展了 ActionBarActivity

              替换为: 公共类 DemoActivity 扩展了 Activity

              【讨论】:

              • 他为什么要这样做?请更详细地解释您的答案。
              • 当我扩展 ActionBarActivity 时,它总是返回 null。但我只扩展了 Activity,它工作正常
              • 在使用 ActionBarActivity 时,您需要使用自己的命名空间,因为它是支持库的一部分。由于您在 xml 中使用 android:showAsAction 它适用于 Activity (不是来自支持库)并且不适用于 ActionBarActivity
              猜你喜欢
              • 2015-11-15
              • 1970-01-01
              • 2014-03-04
              • 2016-11-02
              • 2014-05-06
              • 2012-06-05
              • 2014-05-30
              • 2014-02-23
              相关资源
              最近更新 更多