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>
mContext = getActivity().getApplicationContext();
- I would bet that that's your problem. You're using the v7 appcompatPopupMenu
, and the applicationContext
won't have the right theme resources set on it. Just usegetActivity()
. You really don't need to keep aContext
field, btw. You can callgetActivity()
wherever you need one. – Shrovetidestatic
members in yourFragment
class. Normally, you'd wanna add aContext
parameter to the method to pass one in, but that method is using other static members withContext
s, so it's a moot point here. You'd have to redesign how you're communicating with thatFragment
. Anyhoo, the current issue is likely the wrongContext
, so just removing thegetApplicationContext()
call in the code you have now will let you know if that is indeed the issue. – Shrovetideandroid.view.WindowManager$BadTokenException: Unable to add window -- token android.view.ViewRootImpl$W@f847ac3 is not valid; is your activity running?
I think i might be trying to secure the wrong context, I think I should instead be trying to get the context of the PopupWindow this transaction occurs in. Do you know how I would do this? Or rather, what the source of the issue is? – LipsonPopupMenu
from aPopupWindow
? I don't think that's gonna work. I don't believe you can anchor a popup to another popup. – ShrovetideDialog
instead of thePopupWindow
. – ShrovetideDialog
s don't have any buttons - or any kind ofView
- by default. I think you're thinking ofAlertDialog
. You can make it be just a floatingRecyclerView
, if you want. I don't know what you mean by "interaction-with-parent-view methods". – ShrovetideAlertDialog
; just don't setup any buttons. Remove/comment out themCustomChordMenu.showAtLocation()
line, and insert - just as an example -new AlertDialog.Builder(getActivity()).setView(mPopupView).show();
. – Shrovetide