简体   繁体   English

从数据库填充Spinner时的奇怪行为

[英]Strange Behavior when populating Spinner from Database

I am trying to populate a spinner from Mysql Databse through JSON. 我试图通过JSON从Mysql Databse填充一个微调器。 The thing is that the data are exported fine. 问题是数据导出正常。 But when I click the Spinner to show the dropdown menu the app crashes. 但是,当我单击Spinner显示下拉菜单时,应用程序崩溃了。

The JSON output from database: Output 数据库的JSON输出: 输出

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: 我的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> . 我正在膨胀自定义布局,但它将它作为ArrayAdapter<String>

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. 包含要在实例化视图时使用的TextView的布局文件的资源ID。

You haven't included your xml, does R.layout.spinner_item have a TextView in it? 你没有包含你的xml,R.layout.spinner_item中有一个TextView吗?

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. 您的stacktrace中包含ArrayAdapter ,因为您的SpiritsListAdapter扩展了ArrayAdapter ,因此每次调用super()或调用您未覆盖的ArrayAdapter方法之一时,都会使用ArrayAdapter类中的代码。

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? 编辑:您是否尝试过使用此构造函数: ArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects) (它是链接到上面的页面上的第六个),您可以在其中为其提供所需TextView的ID填充? There could be a problem caused by having two TextView s in the layout (as noted in the comments). 在布局中使用两个TextView可能会导致问题(如注释中所述)。

You can do the same thing using BaseAdapter as such: 您可以使用BaseAdapter执行相同的操作:

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. 并添加未实现的方法,并保持您的getView方法不变。

Hope it helps!!! 希望能帮助到你!!!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM