I'm building an app for ordering food from a resturant. When a user selects an item I hit our server to retrieve a JSON package containing the options for that item. (ex: Bread: White, Wheat).
What I'm trying to do is use a custom list adapter to generate a list of all the options the user needs to select before adding the item to the cart. This is working well, except when I click on the spinner I get:
05-20 15:12:53.602: ERROR/AndroidRuntime(696): FATAL EXCEPTION: main
05-20 15:12:53.602: ERROR/AndroidRuntime(696): 开发者_如何学运维android.view.WindowManager$BadTokenException: Unable to add window -- token android.app.LocalActivityManager$LocalActivityRecord@44e933d8 is not valid; is your activity running?
05-20 15:12:53.602: ERROR/AndroidRuntime(696):at android.view.ViewRoot.setView(ViewRoot.java:505)
05-20 15:12:53.602: ERROR/AndroidRuntime(696):at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
05-20 15:12:53.602: ERROR/AndroidRuntime(696):at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
05-20 15:12:53.602: ERROR/AndroidRuntime(696):at android.view.Window$LocalWindowManager.addView(Window.java:424)
etc...
It has to do with passing the correct context to the array adapter I'm using for the spinner, but I feel like I've tried all possible options. This block is the culprit:
ArrayAdapter<String> adapter = new ArrayAdapter<String> (parent.getContext(), android.R.layout.simple_spinner_item, options);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
attrSpinner.setAdapter(adapter);
Here is the whole custom list adapter, so you can see where I'm using this block:
public class ItemListAdapter extends BaseAdapter {
public ItemListAdapter(Context context) {
Context mContext = context;
}
public int getCount() {
return attributes.length();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View attr_item = li.inflate(R.layout.menu_attributes, null);
TextView attrName = (TextView) attr_item.findViewById(R.id.attr_name);
CheckBox attrCheck = (CheckBox) attr_item.findViewById(R.id.attr_checkbox);
EditText attrText = (EditText) attr_item.findViewById(R.id.attr_edittext);
Spinner attrSpinner = (Spinner) attr_item.findViewById(R.id.attr_spinner);
try {
String attrID = attributes.getJSONObject(position).getString("AttrID");
String type = attributes.getJSONObject(position).getString("Type");
String itemLabel = attributes.getJSONObject(position).getString("ItemLabel");
JSONArray values = attributes.getJSONObject(position).getJSONArray("Values");
if (type.equals("select")) {
attrCheck.setVisibility(View.GONE);
attrText.setVisibility(View.GONE);
ArrayList<String> options = new ArrayList<String>();
for (int i=0;i<values.length();i++) {
options.add(values.getJSONObject(i).getString("Name"));
Log.i("value options", values.getJSONObject(i).getString("Name"));
}
//HERE IS THE PROBLEM
ArrayAdapter<String> adapter = new ArrayAdapter<String> (parent.getContext(), android.R.layout.simple_spinner_item, options);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
attrSpinner.setAdapter(adapter);
}
else if (type.equals("checkbox")){
attrSpinner.setVisibility(View.GONE);
attrText.setVisibility(View.GONE);
}
else if (type.equals("textarea")){
attrSpinner.setVisibility(View.GONE);
attrCheck.setVisibility(View.GONE);
}
else if (type.equals("text")){
attrSpinner.setVisibility(View.GONE);
attrCheck.setVisibility(View.GONE);
}
attrName.setText(itemLabel);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return attr_item;
}
Any help is greatly appreciated. Thanks.
Can you explain how are you using MenuAttributes and LocalActivityRecord?
It is using the latter's Context (android.app.LocalActivityManager$LocalActivityRecord@44e933d8
), while probably you need to provide the MenuAttributes object's Context.
To simplify, I would have an upper level Context context;
field in the MenuAttributes
class (you can set it as this.context = this;
in onCreate()
) and use that field as:
ArrayAdapter<String> adapter = new ArrayAdapter<String> (context, android.R.layout.simple_spinner_item, options);
I couldn't get this to work, so I switched it to radio buttons. Then I ran into another issue with values disappearing from edittext fields when the list is scrolled.
After doing some research I found that putting form controls inside ListView is a very bad idea because it has many bugs in android. See this previous post: http://bit.ly/mhvL1D
I switched to a ScrollView with nested LinearLayouts containing the various form controls.
Magically, all my problems have gone away. The spinner now works great and the EditText no longer disappears on scroll.
I was just going about the whole process wrong.
Lesson Learned: Don't use ListView for form controls.
精彩评论