0

My app is supposed to parse JSON data and display it in a recycler view. When I run the app, it crashes with the following error: enter image description here

I've re-checked my code multiple times to make sure I am calling the correct resource files, but I still cant find the source of the issue. The logcat tells me the issue is in the onBindViewHolder method in the recycler view adapter class, but everything looks normal to me. Can anyone point me in the right direction? Here is the relevant code:

Recycler View Adapter:

    public class IndRvAdapter extends RecyclerView.Adapter<IndRvAdapter.MyViewHolder> {

    private Context context;
    private List<Ind> indList;

    public IndRvAdapter(Context context, List<Ind> indList) {
        this.context = context;
        this.indList = indList;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view;
        LayoutInflater inflater = LayoutInflater.from(context);
        view = inflater.inflate(R.layout.ind_card, viewGroup, false);
        final MyViewHolder viewHolder = new MyViewHolder(view);
        viewHolder.indView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent i = new Intent(context, SingleInd.class);
                i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                i.putExtra("pacshort", indList.get(viewHolder.getAdapterPosition()).getPacshort());
                i.putExtra("supopp", indList.get(viewHolder.getAdapterPosition()).getSuppopp());
                i.putExtra("candname", indList.get(viewHolder.getAdapterPosition()).getCandname());
                i.putExtra("district", indList.get(viewHolder.getAdapterPosition()).getDistrict());
                i.putExtra("amount", indList.get(viewHolder.getAdapterPosition()).getAmount());
                i.putExtra("party", indList.get(viewHolder.getAdapterPosition()).getExpParty());
                i.putExtra("payee", indList.get(viewHolder.getAdapterPosition()).getPayee());
                i.putExtra("date", indList.get(viewHolder.getAdapterPosition()).getDate());
                i.putExtra("origin", indList.get(viewHolder.getAdapterPosition()).getOrigin());
                i.putExtra("source", indList.get(viewHolder.getAdapterPosition()).getSource());
                context.startActivity(i);
            }
        });
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, int i) {
        myViewHolder.pacshorts.setText(indList.get(i).getPacshort());
        myViewHolder.supOpp.setText(indList.get(i).getSuppopp());
        myViewHolder.candName.setText(indList.get(i).getCandname());
        myViewHolder.district.setText(indList.get(i).getDistrict());
    }

    @Override
    public int getItemCount() {
        return indList.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder{
        TextView pacshorts, supOpp, candName, district;
        LinearLayout indView;
        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            pacshorts = itemView.findViewById(R.id.tv_pacshort);
            supOpp = itemView.findViewById(R.id.tv_suppopp);
            candName = itemView.findViewById(R.id.tv_candname);
            district = itemView.findViewById(R.id.tv_district);
            indView = itemView.findViewById(R.id.ind_view);
        }
    }
}

Card View resource:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:id="@+id/ind_view">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:layout_gravity="center"
        android:layout_margin="5dp"
        android:elevation="3dp"
        card_view:cardCornerRadius="15dp"
        card_view:cardElevation="4dp"
        card_view:cardUseCompatPadding="true">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/colorPrimaryDark">

            <TextView
                android:id="@+id/pacshort"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="TextView" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/pacshort"
                android:id="@+id/tv_suppop"/>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/tv_candname"
                android:layout_below="@+id/tv_suppop"/>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/tv_district"
                android:layout_below="@+id/tv_candname"/>
        </RelativeLayout>
    </android.support.v7.widget.CardView>


</LinearLayout>

Recycler View:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/background_color"
    tools:context=".IndExpend">

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/ind_rv">
    </android.support.v7.widget.RecyclerView>

</RelativeLayout>

Main Activity that parses the JSON data

    public class IndExpend extends AppCompatActivity {
    /*
    * Open secrets API: Returns the 50 latest independent expenditures transactions
    * Updated every 4 days
    */

    private static final String url = "http://www.opensecrets.org/api/?method=independentExpend&output=json&apikey=d1ff8f708ca0745d75e9ffa0ee6f3d09";
    private LinearLayoutManager linearLayoutManager;
    private List <Ind> indList;
    private RecyclerView myrv;
    private RecyclerView.Adapter adapter;

    public IndExpend(){}

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

        linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);

        myrv = findViewById(R.id.ind_rv);
        indList = new ArrayList<>();
        adapter = new IndRvAdapter(this, indList);

        myrv.setHasFixedSize(true);
        myrv.setLayoutManager(linearLayoutManager);
        myrv.setAdapter(adapter);

        getData();
    }

    private void getData() {
        final ProgressDialog progressDialog = new ProgressDialog(this);
        progressDialog.setMessage("Loading...");
        progressDialog.show();

        StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                progressDialog.dismiss();
                try {
                    JSONObject object = new JSONObject (response);
                    JSONObject responseObj = object.getJSONObject("response");
                    JSONArray array = responseObj.getJSONArray("indexp");
                    for (int i = 0; i < array.length(); i++){
                        JSONObject attributesObj = array.getJSONObject(i).getJSONObject("@attributes");
                        Ind ind = new Ind(attributesObj.getString("pacshort"),
                                attributesObj.getString("suppopp"),
                                attributesObj.getString("candname"),
                                attributesObj.getString("district"),
                                attributesObj.getString("amount"),
                                attributesObj.getString("party"),
                                attributesObj.getString("payee"),
                                attributesObj.getString("date"),
                                attributesObj.getString("origin"),
                                attributesObj.getString("source"));
                        indList.add(ind);
                    }
                    adapter = new IndRvAdapter(getApplicationContext(), indList);
                    myrv.setAdapter(adapter);
                }catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e("Volley", error.toString());
                progressDialog.dismiss();
            }
        });
        RequestQueue requestQueue = Volley.newRequestQueue(this );
        requestQueue.add(stringRequest);
    }
}

Can anyone help me find the source of the problem?

Gabriel
  • 346
  • 5
  • 24

1 Answers1

0

I think it is because you are trying to bind the view with this id:

pacshorts = itemView.findViewById(R.id.tv_pacshort);

But on the layout file the id for that element its just pacshort:

<TextView
            android:id="@+id/pacshort"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="TextView" />

Generally on these type of null pointer exceptions when working on Android happens for one of two reasons. First, the res file that's being inflated is not the right one or, second, the id used to bind the views is misspelled or doesn't exist in that view.

Sergio Pardo
  • 774
  • 6
  • 17