MenuItemCompat.getActionView luôn trả về null


142

Tôi mới triển khai v7 AppCompatthư viện hỗ trợ nhưng MenuItemCompat.getActionViewluôn trả về null trong mọi phiên bản Android tôi đã thử nghiệm (4.2.2, 2.3.4 ....)

Biểu tượng SearchViewđược hiển thị trên thanh hành động nhưng nó không phản hồi với các hành động chạm và không mở rộng để hiển thị EditTextvà giống như một biểu tượng đơn giản.

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

Câu trả lời:


296

Cuối cùng tôi cũng tìm được giải pháp.

  1. Thay đổi không gian tên actionViewClasstừ android:actionViewClassđếnapp:actionViewClass

  2. android.support.v7.widget.SearchView.OnQueryTextListenerGiao diện triển khai cho hoạt động hiện tại.

  3. Sử dụng trực tiếp setOnQueryTextListenerthay vì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
Nếu điều này giải quyết vấn đề của bạn, có lẽ bạn nên chấp nhận câu trả lời của bạn. Tôi cũng muốn chỉ ra tất cả những người khác có vấn đề tương tự với một chủ đề khác thảo luận về các vấn đề tương tự: stackoverflow.com/q/18407171/1108032 . Nếu chủ đề hiện tại không giải quyết được vấn đề của bạn, hãy xem xét xem xét các giải pháp ở đó.
Boris Strandjev

4
Câu trả lời chính xác! Cũng có thể trả tiền để làm rõ rằng "ứng dụng" trong ứng dụng: actionViewClass cũng yêu cầu một khai báo xmlns bổ sung cho không gian tên "ứng dụng".
jklp

3
Cần phải nói rằng android.support.v7.widget.SearchViewlớp không nên bị nhầm lẫn với lớp 'android.support.v4.widget.SearchViewCompat' (được biết đến như một lỗi phổ biến khi sử dụng thư viện ActionBarCompat)
Alex Semeniuk

1
@jklp Mình thử thêm xmlns khai báo <menu xmlns:app="http://schemas.android.com/apk/res/android" >nhưng gặp lỗi Attribute is missing the Android namespace prefix. Bạn có nhận được nó, và làm thế nào để bạn sửa chữa nó?
an toàn

5
Cũng lưu ý, android: showAsAction cũng cần được thay đổi thành ứng dụng: showAsAction. Đồng thời đảm bảo chủ đề của bạn cho hoạt động (không chỉ ứng dụng) đang tham khảo một chủ đề ứng dụng. Điều cuối cùng, phần khai báo của ứng dụng là " schemas.android.com/apk/res-auto "
Kalel Wade

85

Trong trường hợp của tôi, đó là tệp ProGuard. Bạn cần thêm dòng này:

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

2
Wow, tại sao điều này là một điều? Đây là điều duy nhất làm việc cho tôi.
Claud

2
+1. Khá rõ ràng, nhưng tôi vẫn sẽ đề cập - Trong trường hợp bạn đã mở rộng SearchView sang một lớp khác, hãy giữ đường dẫn đến lớp đó trong proguard!
dùng2520215

42

Đối với tôi, menu.xmlnhập không gian tên không chính xác gây ra vấn đề này.

Bản gốc của tôi 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>

Có vẻ như xmlns:app="http://schemas.android.com/tools"đã gây ra MenuItemCompat.getActionView()trở lại null. Thay đổi nhập này để xmlns:app="http://schemas.android.com/apk/res-auto"khắc phục vấn đề.

Công việc mới 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

Tôi nghĩ rằng vấn đề là bạn sử dụng SearchView từ gói Support V7 và có thể cấp API của bạn được đặt thành ..... 22 ??.

Thay đổi mã của bạn thành như sau để khắc phục sự cố:

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
Bạn có thể giải thích tại sao mẫu mã bạn cung cấp giải quyết vấn đề không? (Tôi cho là có.)
Edgar N

4

Tôi đã có cùng một lỗi, phương pháp của tôi getActionView()luôn luôn trả về null. Vì vậy, tôi đã thực hiện những điều sau đây:

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

Tôi thấy trong một số bài đăng rằng mọi người đang sử dụng ứng dụng: hoặc yourapp, nhưng tôi đã sử dụng bình thường android:ActionVewClass.

Về onCreateOptionsMenuphương pháp của tôi :

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

Và đừng quên đưa vào onCreatephương thức:

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

Điều này hoạt động rất tốt cho hoạt động "mở rộng" của tôi cho FragmentActivityActionBarActivity.


2

Câu trả lời của Mohsen Afshin ở trên là điểm khởi đầu của tôi và tôi đã thực hiện một số điều chỉnh để làm cho nó hoạt động với thiết lập của mình:

@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

Tôi đã có cùng một mã, nhưng thay vì sử dụng nhập android.support.v7.widget.SearchView;tôi đang sử dụng import android.widget.SearchView;. Điều này đã khắc phục vấn đề của tôi với nullgiá trị. Vì vậy, chỉ cần thay đổi mã này trong hoạt động tìm kiếm của bạn và nó sẽ hoạt động và cũng thay đổi không gian tên trong tệp xml.


Đây là vấn đề của chúng tôi, chúng tôi đã kết hợp android.widget.SearchView trong Hoạt động nhưng đã sử dụng một phần v7 trong tệp menu_main.xml của chúng tôi. Chỉ cần đảm bảo tệp .xml cũng đang sử dụng ứng dụng: actionViewClass = "android.support.v7.widget.SearchView".
gmcc051

0

Đây là một đoạn về cách xử lý searchView từ thư viện hỗ trợ 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;
  }

Ngoài ra, nếu bạn sử dụng Proguard, hãy thêm phần này vào cấu hình của nó:

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

Đối với bất cứ ai muốn định dạng mã, đây là một định dạng rất nổi tiếng được gọi là "WhiteSmith". Thay đổi sang định dạng khác không làm cho nó tốt hơn, vì đây là vấn đề của hương vị.
nhà phát triển Android

@JJD Vâng. Chính xác. Nó không phổ biến như những người khác, nhưng tôi đã sử dụng nó trong một thời gian rất dài. Bạn có thể đặt nó trên Eclipse nếu bạn muốn.
nhà phát triển Android

Cám ơn vì đã chia sẻ. Tôi giữ nguyên mặc định vì nó tránh được nhiều cuộc thảo luận không mong muốn với các thành viên trong nhóm hoặc cộng tác viên.
JJD

@JJD Điều đó cũng đúng. tại văn phòng chúng tôi làm việc với một phong cách khác một chút so với phong cách mặc định. Dù sao, một nhà phát triển giỏi sẽ có thể xử lý tất cả các kiểu định dạng phổ biến và nếu nó "làm tổn thương mắt", bạn luôn có thể sao chép mã và định dạng mã trên các công cụ định dạng khác nhau (trực tuyến hoặc trên IDE).
nhà phát triển Android

0

Tôi có một vấn đề rất giống với sự khác biệt là tôi đã cố gắng sử dụng một lớp mở rộng android.widget.ImageView

Nếu bạn đang sử dụng ProGuard, bạn cần chỉ định để cho phép các phương thức liên quan đến lớp này.

-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

Điều này nói, "Cho phép tất cả các hàm tạo cần thiết có thể được gọi từ xml và cho phép mọi setters tùy chỉnh mà nó sử dụng (thêm nhiều hơn khi cần thiết)"


0

Tôi đã làm điều này bằng cách đặt thủ công trong mã 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>

Bố cục tập tin:

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

Sau đó, trong mã 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;
    }

nhập mô tả hình ảnh ở đây


-1

Loại bỏ mã: public class DemoActivity kéo dài ActionBarActivity

Thay thế bằng: lớp công khai DemoActivity mở rộng Hoạt động


2
Tại sao anh ta phải làm như vậy? Hãy giải thích câu trả lời của bạn chi tiết hơn một chút.
Robin Ellerkmann

Khi tôi mở rộng ActionBarActivity, nó luôn trả về null. Nhưng tôi chỉ mở rộng Hoạt động, nó hoạt động bình thường
Hiếu

Bạn cần sử dụng không gian tên của riêng bạn khi sử dụng ActionBarActivity vì đây là một phần của thư viện hỗ trợ. Vì bạn đang sử dụng Android: showAsAction trong xml của mình, nó hoạt động với Activity (không phải từ thư viện hỗ trợ) và không hoạt động với ActionBarActivity
Dennis K
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.