MenuItemCompat.getActionView завжди повертає null


142

Я щойно реалізував v7 AppCompatбібліотеку підтримки, але MenuItemCompat.getActionViewзавжди повертаю нуль у кожній тестованій версії Android (4.2.2, 2.3.4 ....)

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

Меню.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>

Відповіді:


296

Нарешті я знайшов рішення.

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

3
Якщо це вирішило вашу проблему, ви, ймовірно, повинні прийняти вашу відповідь. Я також хотів би вказати всіх інших людей із подібними проблемами на ще одну тему, яка обговорює подібні проблеми: stackoverflow.com/q/18407171/1108032 . Якщо поточна нитка не вирішує ваших проблем, подумайте про її рішення.
Борис Страндєв

4
Чудова відповідь! Можливо, також слід уточнити, що "app" в app: actionViewClass також вимагає додаткового оголошення xmlns для простору імен "app".
jklp

3
Потрібно сказати, що android.support.v7.widget.SearchViewклас не слід плутати з класом 'android.support.v4.widget.SearchViewCompat' (який відомий як поширена помилка при використанні бібліотеки ActionBarCompat)
Олексій Семенюк

1
@jklp Я намагаюся додати декларацію xmlns, <menu xmlns:app="http://schemas.android.com/apk/res/android" >але отримую помилку Attribute is missing the Android namespace prefix. Ви отримуєте це, і як це виправити?
антикафе

5
Також зауважте, android: showAsAction також потрібно змінити на додаток: showAsAction. Також переконайтесь, що ваша тема для діяльності (не лише програми) відповідає темі додатка для додатків. Останнє, декларація програми - " schemas.android.com/apk/res-auto "
Kalel Wade

85

У моєму випадку це був файл ProGuard. Вам потрібно додати цей рядок:

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

2
Нічого собі, чому це річ? Це було єдине, що працювало на мене.
Клод

2
+1. Досить очевидно, але я все одно зазначу - Якщо ви поширили SearchView до іншого класу, тримайте шлях до цього класу у захисті!
користувач2520215

42

Для мене неправильна 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>

5

Я думаю, що проблема полягає в тому, що ви використовуєте SearchView з пакету підтримки V7 і, можливо, ваш рівень 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> 

1
Чи можете ви пояснити, чому наданий вами зразок коду вирішує проблему? (Я припускаю, що так і є.)
Едгар N

4

Я був з тією ж помилкою, мій метод getActionView()завжди повертався на нуль. Отже, я зробив наступні речі:

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

У деяких публікаціях я бачив, що люди використовують додаток: або 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);

Це дуже добре справляється з моєю діяльністю, яка "поширюється" на FragmentActivityта ActionBarActivity.


2

Відповідь Мохсена Афшина вище була моєю відправною точкою, і я зробив декілька налаштувань, щоб змусити це працювати з моєю установкою:

@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

У мене був той самий код, але замість імпорту android.support.v7.widget.SearchView;я використовував import android.widget.SearchView;. Це вирішило мою проблему зі nullзначенням. Тому просто змініть цей код у своїй пошуковій діяльності, і він буде працювати, а також змінити простір імен у файлі xml.


Це було нашою проблемою, у нас було поєднання android.widget.SearchView у діяльності, але частково використовували v7 у нашому файлі menu_main.xml. Просто переконайтеся, що файл .xml також використовує додаток: actionViewClass = "android.support.v7.widget.SearchView" теж.
gmcc051

0

Ось фрагмент, як обробити searchView з бібліотеки підтримки 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;
  }

Крім того, якщо ви використовуєте 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

@JJD Це теж правда. в офісі ми працюємо з дещо іншим стилем, ніж за замовчуванням. У будь-якому випадку, хороший розробник повинен вміти обробляти всі поширені стилі форматування, і якщо це "болить очі", ви завжди можете скопіювати код і відформатувати його на різних інструментах форматування (в Інтернеті чи на IDE).
андроїд розробник

0

У мене була дуже схожа проблема з різницею, оскільки я намагався використовувати клас, який розширюється 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, і дозволити також будь-які власні налаштування, які він використовує (додайте більше за потребою)"


0

Я зробив це вручну, встановленому в коді 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;
    }

введіть тут опис зображення


-1

Видалити код: DemoActivity публічного класу розширює ActionBarActivity

Замініть на: публічний клас DemoActivity розширює Діяльність


2
Чому він повинен це робити? Будь ласка, поясніть свою відповідь трохи детальніше.
Робін Еллеркман

Коли я розширює ActionBarActivity, він завжди повертає null. Але я розширюю лише Активність, вона працює нормально
Hieu

Вам потрібно використовувати власний простір імен при використанні ActionBarActivity, оскільки це частина бібліотеки підтримки. Оскільки ви використовуєте android: showAsAction у вашому xml, він працює з Activity (що не з бібліотеки підтримки) і не працює з ActionBarActivity
Dennis K
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.