The best way to achieve this is in fact to roll your own custom adapter that extends BaseAdapter. I struggled with this issue for a day trying to avoid doing a pointless iteration of a JSONArray just to fill an array and use it in a "normal" ArrayAdapter. My situation was very similar to yours, with the small diference that i wanted to populate a spinner and not a ListView. Despite that, i will post the solution i found, because it may be helpful to you or someone else.
In your activity class:
public void initSpinner(JSONArray jsonArray)
{
Spinner spinner = new Spinner(this);
JSONArrayAdapter jsonArrayAdapter = new JSONArrayAdapter(this, countries, "Name");
spinner.setAdapter(jsonArrayAdapter);
}
NOTE: the string "name" i pass has a parameter to my adapter is simply the key i wish to look for in my json data, in your case, it might be whatever key you are looking for.
Next, you need to roll your own spinner list item, wrapped in a RelativeLayout. I did this in a file called spinner_item.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dip" >
<TextView
android:id="@+id/spinnerListItemName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:textColor="#000000"
android:textSize="16dip" />
<RadioButton
android:id="@+id/spinnerRadioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:paddingRight="6dip"
android:focusable="false"
android:clickable="false" />
<TextView
android:id="@+id/spinnerListItemID"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible" />
</RelativeLayout>
NOTE: the text view with id spinnerListItemID i just use because i want to store the id of the last button that i chose to simulate the behavior of a RadioButtonGroup, its very likely that there is a better way to acomplish this task, this is just the way that i found suited better at the time.
Finally, and most importantly, you need to create your JsonArrayAdapter class:
public class JSONArrayAdapter extends BaseAdapter implements OnTouchListener
{
private ViewGroup group;
private JSONArray items;
private String key;
private Context context;
private String selectedItemID;
private int selectedItemPosition;
public JSONArrayAdapter(Context ctx, JSONArray array, String k)
{
super();
this.items = array;
this.context = ctx;
this.key = k;
this.selectedItemPosition = -1;
}
public int getCount()
{
return items.length();
}
public Object getItem(int position)
{
return position;
}
public long getItemId(int position)
{
return position;
}
public View getView(int position, View convertView, ViewGroup parent)
{
View view = convertView;
group = parent;
if (view == null)
{
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = vi.inflate(R.layout.spinner_item, null);
view.setOnTouchListener(this);
}
String itemText = null;
String itemID = null;
try
{
JSONObject jsonObject = items.getJSONObject(position);
itemText = jsonObject.getString(key);
itemID = jsonObject.getString("ID");
}
catch (JSONException e)
{
}
if (itemText != null)
{
TextView name = (TextView) view.findViewById(R.id.spinnerListItemName);
TextView id = (TextView) view.findViewById(R.id.spinnerListItemID);
RadioButton button = (RadioButton) view.findViewById(R.id.spinnerRadioButton);
if (name != null)
name.setText(itemText);
if (id != null)
{
id.setText(itemID);
id.setHint(position + "");
}
if (id.getText().toString().equals(selectedItemID))
{
button.setSelected(true);
button.setChecked(true);
}
else
{
button.setSelected(false);
button.setChecked(false);
}
}
if (selectedItemPosition == -1 && position == 0)
this.setFirstChosen(view);
return view;
}
private void setFirstChosen(View view)
{
RadioButton button = (RadioButton) view.findViewById(R.id.spinnerRadioButton);
button.setSelected(true);
button.setChecked(true);
selectedItemID = ((TextView) view.findViewById(R.id.spinnerListItemID)).getText().toString();
selectedItemPosition = Integer.parseInt(((TextView) view.findViewById(R.id.spinnerListItemID)).getHint().toString());
}
public boolean onTouch(View v, MotionEvent event)
{
RadioButton button = (RadioButton) v.findViewById(R.id.spinnerRadioButton);
if (selectedItemPosition != -1)
{
View previousView = group.getChildAt(selectedItemPosition);
if (previousView != null)
{
RadioButton previous = (RadioButton) previousView.findViewById(R.id.spinnerRadioButton);
previous.setSelected(false);
previous.setChecked(false);
}
}
button.setSelected(true);
button.setChecked(true);
selectedItemID = ((TextView) v.findViewById(R.id.spinnerListItemID)).getText().toString();
selectedItemPosition = Integer.parseInt(((TextView) v.findViewById(R.id.spinnerListItemID)).getHint().toString());
return false;
}
}
There you have it, worked like a charm for me, and i know the pain it is to find information on this subject on-line :)