简体   繁体   中英

Custom List adapter not working JSON to android list

I am trying to make a custom list adapter by following this tutorial . I'm having trouble when when my object gets items from my JSON data and adds it to the list. I've been able to use the simple list adapter and a hash map. I'd like to get away from the simple list adapter and hash maps. Here is my stack trace:

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)

Here is my 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;
        }

    }

}

Here is my JSON parser class:

    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;

    }
}

The error is coming from line 62 which is this class:

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);
    }

}

and this line:

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

New adapter class:

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);
    }
}

I'm now getting this stack:

    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)

The error seems to be here:

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

Still getting an error at the above line.

here is my get view now:

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);
    }

Try setting Adapter in onPostExecute because you can not update the UI from worker thread.

@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);
        }

Edit:- Define Ammo class like below

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;
    }

}

ViewHolder holder = new ViewHolder(convertView);

In this line, convertView may be null. You need to move this line inside the if block, after you have inflated convertView = inflater.inflate(R.layout.row, null);

as njzk2 said you must move ViewHolder holder = new ViewHolder(convertView); after the creation of the view.

And you must also set convertView.setTag(holder); , otherwise you will have a NullPointerException when getting to 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);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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