Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binary XML Inflate Error on PopupMenu.show() Android

I'm trying to inflate a simple PopupMenu for rename/delete options when a RecylerView item is longClicked. For some reason i'm getting an XML inflate error when I call mPopup.show() after loading my xml file into the inflater.

I use similar logic elsewhere in my app to make a PopupMenu and it works fine. I've even tried loading the working PopupMenu from an unrelated part of the app into this inflater and I see the same android.view.InflateException: Binary XML file line #17: Failed to resolve attribute at index 1 error in logcat, so maybe the XML file isn't the problem?

How can I get this PopupMenu to inflate and show itself?

Fatal Exception 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>
like image 278
Cody Avatar asked Jun 01 '17 03:06

Cody


1 Answers

The cause of the immediate issue here - the InflateException - was using the application Context for an appcompat-v7 PopupMenu.

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

That Context won't have the correct theme resources set for a v7 widget, leading to the InflateException. The Activity does have the appropriate theme, though, and using that instead solves that particular issue.

mContext = getActivity();

After fixing that, however, a WindowManager$BadTokenException came up due to the PopupMenu being passed an anchor View from a PopupWindow. Popups must be anchored to a View in a top-level Window, and the Popup* classes are basically simple Views, thus the Exception.

A simple solution for this is to replace the PopupWindow with a Dialog, which does have a Window. For example:

AlertDialog dlg = new AlertDialog.Builder(getActivity()).setView(mPopupView).show();

Lastly, I would suggest that you modify your setup to remove the need for the static members in your Fragment class. Those static fields are likely to cause memory leaks, and your IDE may very well be warning you of that now. A listener interface similar to the one you have in CustomChordAdapter would suffice.

like image 119
Mike M. Avatar answered Sep 29 '22 05:09

Mike M.