自定义列表适配器无法使用JSON到Android列表

时间:2013-10-31 17:11:00

标签: java android json listadapter

我正在尝试按照此tutorial制作自定义列表适配器。当我的对象从我的JSON数据中获取项目并将其添加到列表中时,我遇到了麻烦。我已经能够使用简单的列表适配器和哈希映射。我想摆脱简单的列表适配器和哈希映射。这是我的堆栈跟踪:

10-31 13:17:19.985: E/AndroidRuntime(15047): FATAL EXCEPTION: main
10-31 13:17:19.985: E/AndroidRuntime(15047): java.lang.NullPointerException
10-31 13:17:19.985: E/AndroidRuntime(15047):    at com.almyz125.ammobot.MainActivity$ViewHolder.<init>(MainActivity.java:62)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at com.almyz125.ammobot.MainActivity$FancyAdapter.getView(MainActivity.java:44)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.widget.AbsListView.obtainView(AbsListView.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.widget.ListView.measureHeightOfChildren(ListView.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.widget.ListView.onMeasure(ListView.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.View.measure(View.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.widget.RelativeLayout.measureChild(RelativeLayout.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.widget.RelativeLayout.onMeasure(RelativeLayout.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.View.measure(View.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.widget.FrameLayout.onMeasure(FrameLayout.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.View.measure(View.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at com.android.internal.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.View.measure(View.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.widget.FrameLayout.onMeasure(FrameLayout.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.View.measure(View.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.Choreographer$CallbackRecord.run(Choreographer.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.Choreographer.doCallbacks(Choreographer.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.Choreographer.doFrame(Choreographer.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.os.Handler.handleCallback(Handler.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.os.Handler.dispatchMessage(Handler.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.os.Looper.loop(Looper.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at android.app.ActivityThread.main(ActivityThread.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at java.lang.reflect.Method.invokeNative(Native Method)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at java.lang.reflect.Method.invoke(Method.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:115)
10-31 13:17:19.985: E/AndroidRuntime(15047):    at dalvik.system.NativeStart.main(Native Method)

这是我的main_activity:

package com.almyz125.ammobot;

import java.util.ArrayList;

import org.json.JSONArray;
import org.json.JSONObject;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends Activity {

    private String apiURLBase, ammoCat;
    private ProgressDialog pDialog;
    ArrayList<Ammo> arrayJSONList = new ArrayList<Ammo>();
    private JSONArray ammos;
    private FancyAdapter fa = null;

    public class Ammo {
        public String href;
        public String desc;
        public String stock;
        public String price;
        public String rd;
    }

    public class FancyAdapter extends ArrayAdapter<Ammo> {
        FancyAdapter() {
            super(MainActivity.this, android.R.layout.simple_list_item_1,
                    arrayJSONList);
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = new ViewHolder(convertView);

            if (convertView == null) {
                LayoutInflater inflater = getLayoutInflater();
                convertView = inflater.inflate(R.layout.row, null);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            holder.populateFrom(arrayJSONList.get(position));
            return (convertView);
        }
    }

    public class ViewHolder {
        public TextView desc = null, href = null, round = null,
                stock = null, price = null;

        ViewHolder(View row) {
            desc = (TextView) row.findViewById(R.id.desc);
            href = (TextView) row.findViewById(R.id.href);
            round = (TextView) row.findViewById(R.id.rd);
            stock = (TextView) row.findViewById(R.id.stock);
            price = (TextView) row.findViewById(R.id.price);
        }

        void populateFrom(Ammo r) {
            desc.setText(r.desc);
            href.setText(r.href);
            round.setText(r.rd);
            stock.setText(r.stock);
            price.setText(r.price);
        }

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        apiURLBase = getString(R.string.api_base_url);
        ammoCat = "22lr";

        new GetJSONTask().execute();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    private class GetJSONTask extends AsyncTask<String, Void, ArrayList<Ammo>> {


        @Override
        protected void onPreExecute() {
            if (pDialog != null) {
                pDialog.dismiss();
            }

            pDialog = new ProgressDialog(MainActivity.this);
            pDialog.setMessage("Please wait..");
            pDialog.setIndeterminate(true);
            pDialog.setCancelable(false);
            pDialog.show();
        }

        @Override
        protected void onPostExecute(ArrayList<Ammo> valid) {
            if (pDialog != null) {
                pDialog.dismiss();
            }

                            ListView lv = (ListView)findViewById(R.id.mainList);
            fa = new FancyAdapter();
            lv.setAdapter(fa);

        }

        @Override
        protected ArrayList<Ammo> doInBackground(String... arg0) {

            try {
                JSONParser jParser = new JSONParser();
                JSONObject json = jParser.getJSONFromUrl(apiURLBase + ammoCat);
                ammos = json.getJSONArray(ammoCat);

                //System.out.println(ammos.toString());

                for (int i = 0; i < ammos.length(); i++) {
                    JSONObject json_data = ammos.getJSONObject(i);

                    Ammo resultRow = new Ammo();
                    resultRow.desc = json_data.getString("desc");
                    resultRow.href = json_data.getString("href");
                    resultRow.price = json_data.getString("price");
                    resultRow.stock = json_data.getString("stock");
                    resultRow.rd = json_data.getString("rd");

                    arrayJSONList.add(resultRow);
                }

            } catch (Exception e) {
                Log.e(ammoCat, "Error:", e);
            }

            return arrayJSONList;
        }

    }

}

这是我的JSON解析器类:

    package com.almyz125.ammobot;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

public class JSONParser {

    static InputStream is = null;
    static JSONObject jObj = null;
    static String json = "";

    // constructor
    public JSONParser() {

    }

    public JSONObject getJSONFromUrl(String url) {

        // Making HTTP request
        try {
            // defaultHttpClient
            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpPost httpPost = new HttpPost(url);

            HttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            is = httpEntity.getContent();           

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    is, "iso-8859-1"), 8);
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
            is.close();
            json = sb.toString();
        } catch (Exception e) {
            Log.e("Buffer Error", "Error converting result " + e.toString());
        }

        // try parse the string to a JSON object
        try {
            jObj = new JSONObject(json);
        } catch (JSONException e) {
            Log.e("JSON Parser", "Error parsing data " + e.toString());
        }

        // return JSON String
        return jObj;

    }
}

错误来自第62行,即第62行:

public class ViewHolder {
    public TextView desc = null, href = null, round = null,
            stock = null, price = null;

    ViewHolder(View row) {
        desc = (TextView) row.findViewById(R.id.desc);
        href = (TextView) row.findViewById(R.id.href);
        round = (TextView) row.findViewById(R.id.rd);
        stock = (TextView) row.findViewById(R.id.stock);
        price = (TextView) row.findViewById(R.id.price);
    }

    void populateFrom(Ammo r) {
        desc.setText(r.desc);
        href.setText(r.href);
        round.setText(r.rd);
        stock.setText(r.stock);
        price.setText(r.price);
    }

}

和这一行:

desc = (TextView) row.findViewById(R.id.desc);

新的适配器类:

public class FancyAdapter extends ArrayAdapter<Ammo> {
    FancyAdapter() {
        super(MainActivity.this, android.R.layout.simple_list_item_1,
                arrayJSONList);
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        if (convertView == null) {
            LayoutInflater inflater = getLayoutInflater();
            convertView = inflater.inflate(R.layout.row, null);
            holder = new ViewHolder(convertView);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.populateFrom(arrayJSONList.get(position));
        return (convertView);
    }
}

我现在正在获得这个堆栈:

    10-31 13:30:27.065: E/AndroidRuntime(16085): FATAL EXCEPTION: main
10-31 13:30:27.065: E/AndroidRuntime(16085): java.lang.NullPointerException
10-31 13:30:27.065: E/AndroidRuntime(16085):    at com.almyz125.ammobot.MainActivity$FancyAdapter.getView(MainActivity.java:53)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.widget.AbsListView.obtainView(AbsListView.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.widget.ListView.measureHeightOfChildren(ListView.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.widget.ListView.onMeasure(ListView.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.View.measure(View.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.widget.RelativeLayout.measureChild(RelativeLayout.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.widget.RelativeLayout.onMeasure(RelativeLayout.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.View.measure(View.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.widget.FrameLayout.onMeasure(FrameLayout.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.View.measure(View.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at com.android.internal.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.View.measure(View.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.widget.FrameLayout.onMeasure(FrameLayout.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.View.measure(View.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.Choreographer$CallbackRecord.run(Choreographer.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.Choreographer.doCallbacks(Choreographer.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.Choreographer.doFrame(Choreographer.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.os.Handler.handleCallback(Handler.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.os.Handler.dispatchMessage(Handler.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.os.Looper.loop(Looper.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at android.app.ActivityThread.main(ActivityThread.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at java.lang.reflect.Method.invokeNative(Native Method)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at java.lang.reflect.Method.invoke(Method.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:115)
10-31 13:30:27.065: E/AndroidRuntime(16085):    at dalvik.system.NativeStart.main(Native Method)

错误似乎在这里:

    holder.populateFrom(arrayJSONList.get(position));

上述行仍然出现错误。

这是我现在的观点:

public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;

        if (convertView == null) {
            LayoutInflater inflater = getLayoutInflater();
            convertView = inflater.inflate(R.layout.row, null);
            convertView.setTag(holder);
            holder = new ViewHolder(convertView);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.populateFrom(arrayJSONList.get(position));
        return (convertView);
    }

3 个答案:

答案 0 :(得分:0)

尝试在onPostExecute 中设置适配器,因为您无法从工作线程更新UI。

@Override
        protected void onPostExecute(ArrayList<Ammo> valid) {
            if (pDialog != null) {
                pDialog.dismiss();
            }
           ListView lv = (ListView)findViewById(R.id.mainList);
            fa = new FancyAdapter();
            lv.setAdapter(fa);
        }

修改: - 定义Ammo类,如下所示

public class Ammo {
    public String href;
    public String desc;
    public String stock;
    public String price;
    public String rd;

    public Ammo(String href, String desc, String stock, String price, String rd) {
        this.href = href;
        this.desc = desc;
        this.stock = stock;
        this.price = price;
        this.rd = rd;
    }

    public String getHref() {
        return href;
    }

    public String getDesc() {
        return desc;
    }

    public String getStock() {
        return stock;
    }

    public String getPrice() {
        return price;
    }

    public String getRd() {
        return rd;
    }

}

答案 1 :(得分:0)

ViewHolder holder = new ViewHolder(convertView);

在这一行中,convertView可能为null。在充气convertView = inflater.inflate(R.layout.row, null);

之后,您需要在if块内移动此行

答案 2 :(得分:0)

正如njzk2所说,你必须在创建视图后移动ViewHolder holder = new ViewHolder(convertView);

您还必须设置convertView.setTag(holder);,否则在访问NullPointerException时会有holder = (ViewHolder) convertView.getTag();

    public View getView(int position, View convertView, ViewGroup parent) 
    {
        if (convertView == null) {
            LayoutInflater inflater = getLayoutInflater();
            convertView = inflater.inflate(R.layout.row, null);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        ViewHolder holder = new ViewHolder(convertView);
        convertView.setTag(holder);

        holder.populateFrom(arrayJSONList.get(position));
        return (convertView);
    }