当RecylerView项被longClicked时,我试图为重命名/删除选项添加一个简单的PopupMenu。由于某种原因,在将xml文件加载到充气机中后调用mPopup.show()时,出现XML充气错误。

我在应用程序的其他地方使用了类似的逻辑来制作PopupMenu,并且效果很好。我什至尝试将应用程序无关部分的工作PopupMenu加载到该充气机中,并且在logcat中看到相同的android.view.InflateException: Binary XML file line #17: Failed to resolve attribute at index 1错误,所以也许XML文件不是问题吗?

我怎样才能使PopupMenu膨胀并显示出来?

致命异常Logcat

05-31 23:02:27.421 19597-20019/? E/AndroidRuntime: FATAL EXCEPTION: main
                                               Process: com.example.foo, PID: 19597
                                               android.view.InflateException: Binary XML file line #17: Failed to resolve attribute at index 1: TypedValue{t=0x2/d=0x7f01005d a=-1}
                                               Caused by: java.lang.UnsupportedOperationException: Failed to resolve attribute at index 1: TypedValue{t=0x2/d=0x7f01005d a=-1}
                                                   at android.content.res.TypedArray.getLayoutDimension(TypedArray.java:761)
                                                   at android.view.ViewGroup$LayoutParams.setBaseAttributes(ViewGroup.java:7060)
                                                   at android.view.ViewGroup$MarginLayoutParams.<init>(ViewGroup.java:7241)
                                                   at android.widget.FrameLayout$LayoutParams.<init>(FrameLayout.java:438)
                                                   at android.widget.FrameLayout.generateLayoutParams(FrameLayout.java:370)
                                                   at android.widget.FrameLayout.generateLayoutParams(FrameLayout.java:369)
                                                   at android.view.LayoutInflater.inflate(LayoutInflater.java:505)
                                                   at android.view.LayoutInflater.inflate(LayoutInflater.java:426)
                                                   at android.support.v7.view.menu.MenuAdapter.getView(MenuAdapter.java:93)
                                                   at android.support.v7.view.menu.MenuPopup.measureIndividualMenuWidth(MenuPopup.java:160)
                                                   at android.support.v7.view.menu.StandardMenuPopup.tryShow(StandardMenuPopup.java:153)
                                                   at android.support.v7.view.menu.StandardMenuPopup.show(StandardMenuPopup.java:187)
                                                   at android.support.v7.view.menu.MenuPopupHelper.showPopup(MenuPopupHelper.java:290)
                                                   at android.support.v7.view.menu.MenuPopupHelper.tryShow(MenuPopupHelper.java:175)
                                                   at android.support.v7.view.menu.MenuPopupHelper.show(MenuPopupHelper.java:141)
                                                   at android.support.v7.widget.PopupMenu.show(PopupMenu.java:233)
                                                   at com.example.foo.FragmentChordMenu.showChordOptionsMenu(FragmentChordMenu.java:132)
                                                   at com.example.foo.CustomChordAdapter$ChordViewHolder$2.onLongClick(CustomChordAdapter.java:138)
                                                   at android.view.View.performLongClickInternal(View.java:5687)
                                                   at android.view.View.performLongClick(View.java:5645)
                                                   at android.view.View.performLongClick(View.java:5663)
                                                   at android.view.View$CheckForLongPress.run(View.java:22234)
                                                   at android.os.Handler.handleCallback(Handler.java:751)
                                                   at android.os.Handler.dispatchMessage(Handler.java:95)
                                                   at android.os.Looper.loop(Looper.java:154)
                                                   at android.app.ActivityThread.main(ActivityThread.java:6077)
                                                   at java.lang.reflect.Method.invoke(Native Method)
                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

FragmentActivity
public class FragmentChordMenu extends Fragment implements CustomChordAdapter.onItemClickListener {
    private static RecyclerView mCustomChordList;
    private static CustomChordAdapter mRecyclerViewAdapter;
    private static Context mContext;

    private FloatingActionButton mFAB;
    private View mPopupView;
    private PopupWindow mCustomChordMenu;

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        mRecyclerViewAdapter = new CustomChordAdapter(this);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        mContext = getActivity().getApplicationContext();   //stores application context for later use in fragment without risk
                                                            //of detachment

        View v = inflater.inflate(R.layout.menu_fragment_chord, container, false);
        LayoutInflater layoutInflater = (LayoutInflater)getActivity().getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        ...

        mFAB = (FloatingActionButton) v.findViewById(R.id.addChord);
        mFAB.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                mCustomChordMenu.showAtLocation(mPopupView, Gravity.CENTER, 10, 10);
                mCustomChordList = (RecyclerView) mPopupView.findViewById(R.id.rv_userChords);
                LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
                mCustomChordList.setLayoutManager(layoutManager);
                mCustomChordList.setAdapter(mRecyclerViewAdapter);
            }
        });

        return v;
    }

    public static void showChordOptionsMenu(final int position){
        View anchorView = mCustomChordList.findViewHolderForAdapterPosition(position).itemView;
        PopupMenu mPopup = new PopupMenu(mContext, anchorView);
        mPopup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                switch (item.getItemId()){
                    case R.id.delete:
                        mRecyclerViewAdapter.deleteChord(position);
                        return true;
                    case R.id.rename:
                        Log.d("FragmentChordMenu: ", "Rename clicked");
                }
                return true;
            }
        });

        MenuInflater popupInflater = mPopup.getMenuInflater();
        popupInflater.inflate(R.menu.popup_delete_chord, mPopup.getMenu());
        mPopup.show();              //ERROR HERE
    }

    ...
}

PopupMenu XML
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content">
    <item
        android:id="@+id/rename"
        android:title="@string/rename"/>

    <item
        android:id="@+id/delete"
        android:title="@string/delete"/>
</menu>

FragmentActivity XML
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                xmlns:android.support.design="http://schemas.android.com/tools"
                android:id="@+id/chordMenu"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

    <ScrollView
        android:id="@+id/scrollview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/chordButtons"
                android:orientation="vertical"  >
            </LinearLayout>

            <android.support.design.widget.FloatingActionButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_margin="16dp"
                android:clickable="true"
                app:fabSize="mini"
                android:id="@+id/addChord"
                app:borderWidth="0dp"
                app:useCompatPadding="false"
                android:src="@drawable/ic_add_black_24dp"/>
        </LinearLayout>

    </ScrollView>

</RelativeLayout>

最佳答案

此处直接出现问题的原因-InflateException-使用appcompat-v7 Context的应用程序PopupMenu

mContext = getActivity().getApplicationContext();
...
PopupMenu mPopup = new PopupMenu(mContext, anchorView);

Context不会为v7小部件设置正确的主题资源,从而导致InflateExceptionActivity确实具有适当的主题,使用该主题可以解决该特定问题。
mContext = getActivity();

但是,在解决此问题之后,由于WindowManager$BadTokenExceptionPopupMenu传递了 anchor View,因此出现了PopupWindow。弹出窗口必须在顶级View中 anchor 定到Window,并且Popup*类基本上是简单的View,因此是Exception。

一个简单的解决方案是将PopupWindow替换为确实具有DialogWindow。例如:
AlertDialog dlg = new AlertDialog.Builder(getActivity()).setView(mPopupView).show();

最后,我建议您修改设置,以消除对static类中的Fragment成员的需要。这些static字段可能会导致内存泄漏,并且您的IDE可能现在就警告您。一个类似于CustomChordAdapter中的监听器接口(interface)就足够了。

关于java - Android上PopupMenu.show()的二进制XML膨胀错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44298079/

10-09 03:57