I am trying to populate a spinner from Mysql Databse through JSON. The thing is that the data are exported fine. But when I click the Spinner to show the dropdown menu the app crashes.
The JSON output from database: Output
The Error:
03-01 18:12:42.966 3214-3214/com.order.app.order E/ArrayAdapter﹕ You must supply a resource ID for a TextView
03-01 18:12:42.966 3214-3214/com.order.app.order D/AndroidRuntime﹕ Shutting down VM
03-01 18:12:42.967 3214-3214/com.order.app.order E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.order.app.order, PID: 3214
java.lang.IllegalStateException: ArrayAdapter requires the resource ID to be a TextView
at android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.java:386)
at android.widget.ArrayAdapter.getDropDownView(ArrayAdapter.java:415)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Caused by: java.lang.ClassCastException: android.widget.RelativeLayout cannot be cast to android.widget.TextView
at android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.java:379)
at android.widget.ArrayAdapter.getDropDownView(ArrayAdapter.java:415)
My Adapter:
public class SpiritsListAdapter extends ArrayAdapter<SpiritList> {
public SpiritsListAdapter(Context context, int layoutId, List<SpiritList> items) {
super(context, layoutId, items);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
SpiritHolderItems holder;
if(convertView == null){
LayoutInflater vi;
vi = LayoutInflater.from(getContext());
convertView = vi.inflate(R.layout.spinner_item, parent, false);
holder = new SpiritHolderItems();
holder.spiritName = (TextView)convertView.findViewById(R.id.spirit_name);
holder.spiritPrice = (TextView)convertView.findViewById(R.id.spirit_price);
convertView.setTag(holder);
}else{
holder = (SpiritHolderItems) convertView.getTag();
}
SpiritList current = getItem(position);
holder.spiritName.setText(current.getName());
holder.spiritPrice.setText(current.getPrice() + " €");
return convertView;
}
static class SpiritHolderItems {
TextView spiritName, spiritPrice;
}
}
My AsyncTask:
public class JsonReadTask extends AsyncTask<String , Void, List<SpiritList>> {
public JsonReadTask() {
super();
}
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(Gins.this, ProgressDialog.THEME_DEVICE_DEFAULT_DARK);
pDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pDialog.setIndeterminate(true);
pDialog.setMessage(getString(R.string.get_stocks));
pDialog.setCancelable(false);
pDialog.setInverseBackgroundForced(true);
pDialog.show();
}
@Override
protected List<SpiritList> doInBackground(String... params) {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(params[0]);
try {
HttpResponse response = httpclient.execute(httppost);
jsonResult = inputStreamToString(
response.getEntity().getContent()).toString();
customList = new ArrayList<>();
JSONObject jsonResponse = new JSONObject(jsonResult);
JSONArray jsonMainNode = jsonResponse.optJSONArray("gins");
for (int i = 0; i < jsonMainNode.length(); i++) {
JSONObject jsonChildNode = jsonMainNode.getJSONObject(i);
String name = jsonChildNode.optString("name");
String price = jsonChildNode.optString("price");
customList.add(new SpiritList(name, price));
}
return customList;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private StringBuilder inputStreamToString(InputStream is) {
String rLine = "";
StringBuilder answer = new StringBuilder();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
try {
while ((rLine = rd.readLine()) != null) {
answer.append(rLine);
}
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
return answer;
}
@Override
protected void onPostExecute(List<SpiritList> customList) {
if(customList == null){
Log.d("ERORR", "No result to show.");
return;
}
ListDrawer(customList);
pDialog.dismiss();
}
}// end async task
public void accessWebService() {
JsonReadTask task = new JsonReadTask();
task.execute(new String[]{url});
}
public void ListDrawer(List<SpiritList> customList) {
adapterGins = new SpiritsListAdapter(getApplicationContext(), R.layout.spinner_item, customList);
adapterGins.notifyDataSetChanged();
spDrinks.setAdapter(adapterGins);
Log.d("Spinner Count", "The Spinner count is " + spDrinks.getCount());
}
My Layout looks like:
Any ideas why is this happening? I am inflating the custom layout and yet it takes it as an ArrayAdapter<String>
.
You can do the same thing using BaseAdapter as such:
public class SpiritsListAdapter extends BaseAdapter
Modify your constructor like this:
private List<SpiritList> objects;
private Context context;
public SpiritsListAdapter(Context context ,List<SpiritList> objects) {
this.context = context;
this.objects = objects;
}
@Override
public int getCount() {
return objects.size();
}
@Override
public Object getItem(int position) {
return objects.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
and add the unimplemented methods and you keep your getView method as it is.
Hope it helps!!!
You're using the fifth constructor list on this page, which requires that your second parameter be
The resource ID for a layout file containing a TextView to use when instantiating views.
You haven't included your xml, does R.layout.spinner_item have a TextView
in it?
Your stacktrace has ArrayAdapter
in it because your SpiritsListAdapter
extends ArrayAdapter
, so every time you call super()
or one of the ArrayAdapter
's methods that you haven't overriden is called, code from the ArrayAdapter
class is used.
Edit: Have you tried using this constuctor: ArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects)
(it's the sixth one on the page linked to above) where you give it the id of the TextView
you want to populate? There could be a problem caused by having two TextView
s in the layout (as noted in the comments).