MenuItemCompat.getActionView selalu mengembalikan nol

142

Saya baru saja mengimplementasikan v7 AppCompatperpustakaan dukungan tetapi MenuItemCompat.getActionViewselalu mengembalikan nol di setiap versi Android yang saya uji (4.2.2, 2.3.4 ....)

The SearchViewditampilkan dalam tindakan bar tetapi tidak merespon sentuhan tindakan dan tidak memperluas untuk menunjukkan nya EditTextdan hanya seperti ikon sederhana.

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

Jawaban:

296

Akhirnya saya menemukan solusinya.

  1. Mengubah namespace dari actionViewClassdari android:actionViewClassmenjadiapp:actionViewClass

  2. Menerapkan android.support.v7.widget.SearchView.OnQueryTextListenerantarmuka untuk aktivitas saat ini.

  3. Langsung gunakan setOnQueryTextListenerbukanSearchViewCompat.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
sumber
3
Jika ini menyelesaikan masalah Anda, Anda mungkin harus menerima jawaban Anda. Saya juga ingin menunjukkan semua orang lain dengan masalah yang sama ke satu utas lagi yang membahas masalah serupa: stackoverflow.com/q/18407171/1108032 . Jika utas saat ini tidak menyelesaikan masalah Anda, pertimbangkan untuk mencari solusi di sana.
Boris Strandjev
4
Jawaban bagus! Mungkin perlu juga untuk menjelaskan bahwa "app" di app: actionViewClass juga memerlukan deklarasi xmlns tambahan untuk namespace "app".
jklp
3
Perlu untuk mengatakan bahwa android.support.v7.widget.SearchViewkelas tidak boleh bingung dengan kelas 'android.support.v4.widget.SearchViewCompat' (yang dikenal sebagai kesalahan umum saat menggunakan perpustakaan ActionBarCompat)
Alex Semeniuk
1
@ jklp Saya mencoba menambahkan deklarasi xmlns <menu xmlns:app="http://schemas.android.com/apk/res/android" >tetapi mendapatkan kesalahan Attribute is missing the Android namespace prefix. Apakah Anda mendapatkannya, dan bagaimana cara memperbaikinya?
anticafe
5
Perhatikan juga, android: showAsAction perlu diubah ke aplikasi: showAsAction juga. Pastikan juga tema Anda untuk aktivitas (bukan hanya aplikasi) merujuk pada tema appcompat. Hal terakhir, deklarasi aplikasi adalah " schemas.android.com/apk/res-auto "
Kalel Wade
85

Dalam kasus saya itu adalah file ProGuard. Anda perlu menambahkan baris ini:

-keep class android.support.v7.widget.SearchView { *; }
Ivan Vazhnov
sumber
2
Wow, mengapa ini penting? Ini adalah satu-satunya hal yang berhasil untuk saya.
Claud
2
+1. Cukup jelas, tetapi saya masih akan menyebutkan - Jika Anda telah memperluas SearchView ke kelas lain, tetap ikuti jalur ke kelas itu di proguard!
user2520215
42

Bagi saya, menu.xmlimpor namespace yang salah menyebabkan masalah ini.

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

Sepertinya xmlns:app="http://schemas.android.com/tools"menyebabkan MenuItemCompat.getActionView()kembali null. Mengubah impor ini untuk xmlns:app="http://schemas.android.com/apk/res-auto"memperbaiki masalah.

Kerja baru 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
sumber
5

Saya pikir masalahnya adalah Anda menggunakan SearchView dari paket Support V7 dan mungkin level API Anda diatur ke ..... 22 ??.

Mengubah kode Anda menjadi yang berikut untuk memperbaiki masalah:

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
sumber
1
Bisakah Anda menjelaskan mengapa sampel kode yang Anda berikan memecahkan masalah? (Saya berasumsi demikian.)
Edgar N
4

Saya dengan kesalahan yang sama, metode saya getActionView()selalu mengembalikan nol. Jadi, saya sudah membuat hal-hal berikut:

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

Saya melihat di beberapa posting bahwa orang-orang menggunakan aplikasi: atau aplikasi Anda, tetapi saya telah menggunakan secara normal android:ActionVewClass.

Pada onCreateOptionsMenumetode saya :

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

Dan jangan lupa untuk memasukkan onCreatemetode:

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

Ini bekerja sangat baik untuk aktivitas saya "memperluas" untuk FragmentActivitydan ActionBarActivity.

Franzé Jr.
sumber
2

Jawaban Mohsen Afshin di atas adalah titik awal saya dan saya membuat beberapa penyesuaian untuk membuatnya bekerja dengan pengaturan saya:

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

Saya memiliki kode yang sama, tetapi alih-alih menggunakan impor yang android.support.v7.widget.SearchView;saya gunakan import android.widget.SearchView;. Ini memperbaiki masalah saya dengan nullnilai. Jadi, ubah saja kode ini dalam aktivitas pencarian Anda dan itu akan bekerja dan juga mengubah namespace dalam file xml.

marcelocolombo
sumber
Ini adalah masalah kami, kami memiliki campuran android.widget.SearchView dalam Aktivitas tetapi menggunakan sebagian v7 dalam file menu_main.xml kami. Pastikan saja file .xml juga menggunakan aplikasi: actionViewClass = "android.support.v7.widget.SearchView" juga.
gmcc051
0

Berikut cuplikan cara menangani searchView dari pustaka dukungan 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;
  }

Juga, jika Anda menggunakan Proguard, tambahkan ini ke konfigurasinya:

-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class android.support.v7.widget.SearchView { *; }
-keepattributes *Annotation*
pengembang android
sumber
Bagi siapa pun yang ingin memformat kode, ini adalah format yang sangat dikenal yang disebut "WhiteSmith". Mengubah ke format lain tidak membuatnya lebih baik, karena ini masalah selera.
pengembang android
@ JJD Ya. Benar. Ini tidak biasa seperti yang lain, tapi saya sudah menggunakannya untuk waktu yang sangat lama. Anda dapat mengaturnya di Eclipse jika Anda mau.
pengembang android
Terima kasih telah berbagi. Saya tetap menggunakan default karena menghindari banyak diskusi yang tidak diinginkan dengan anggota tim atau kontributor.
JJD
@JJD Itu juga benar. di kantor kami bekerja dengan gaya yang sedikit berbeda dari yang standar. Bagaimanapun, pengembang yang baik harus dapat menangani semua gaya pemformatan umum, dan jika "menyakitkan mata" Anda selalu dapat menyalin kode dan memformatnya pada berbagai alat pemformatan (online, atau pada IDE).
pengembang android
0

Saya memiliki masalah yang sangat mirip dengan perbedaannya adalah saya mencoba menggunakan kelas yang diperluas android.widget.ImageView

Jika Anda menggunakan ProGuard, Anda perlu menentukan untuk mengizinkan metode yang terlibat dalam kelas ini.

-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

Ini mengatakan, "Izinkan semua konstruktor yang diperlukan yang mungkin dipanggil dari xml dan memungkinkan setter kustom apa pun yang digunakannya (tambahkan lebih banyak sesuai kebutuhan)"

ElliotM
sumber
0

Saya melakukan ini dengan set manual dalam kode 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 tata letak:

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

Kemudian dalam kode 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;
    }

masukkan deskripsi gambar di sini

nobjta_9x_tq
sumber
-1

Hapus kode: DemoActivity kelas publik memperluas ActionBarActivity

Ganti dengan: DemoActivity kelas publik memperluas Aktivitas

Hieu
sumber
2
Kenapa dia harus melakukannya? Tolong jelaskan jawaban Anda sedikit lebih detail.
Robin Ellerkmann
Ketika saya memperluas ActionBarActivity, itu selalu mengembalikan nol. Tapi saya hanya memperluas Kegiatan, itu berfungsi normal
Hieu
Anda perlu menggunakan namespace Anda sendiri ketika menggunakan ActionBarActivity karena merupakan bagian dari pustaka dukungan. Karena Anda menggunakan Android: showAsAction di xml Anda, ia bekerja dengan Activity (yang bukan dari perpustakaan dukungan) dan tidak bekerja dengan ActionBarActivity
Dennis K