1

I have a recyclerView that it get me crash :

enter image description here

Here is my StartActivity :

public class StartActivity extends AppCompatActivity {

    TextView txtTest;
    private ProgressDialog pDialog;
    // These tags will be used to cancel the requests
    private String tag_json_obj = "jobj_req", tag_json_arry = "jarray_req";

    private RecyclerView.Adapter mAdapter;
    RecyclerView UserCode_Recycler;
    private LinearLayoutManager mLayoutManager;


    List<Marketing_Code> userCodeList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_start);
        txtTest = (TextView) findViewById(R.id.txtTest);
        UserCode_Recycler = (RecyclerView) findViewById(R.id.UserCode_Recycler);
        pDialog = new ProgressDialog(this);
        pDialog.setMessage("Loading...");
        pDialog.setCancelable(false);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        if (fab != null) {
            fab.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                            .setAction("Action", null).show();
                }
            });
        }

        makeJsonArryReq();

        userCodeList = new ArrayList<>();
        // create an Object for Adapter
        mAdapter = new UserCodeList_Adapter(userCodeList, StartActivity.this);
        // set the adapter object to the Recyclerview
        UserCode_Recycler.setAdapter(mAdapter);

        mAdapter.notifyDataSetChanged();


        UserCode_Recycler.setHasFixedSize(true);

        mLayoutManager = new LinearLayoutManager(this);
        // use a linear layout manager
        UserCode_Recycler.setLayoutManager(mLayoutManager);

    }

    private void showProgressDialog() {
        if (!pDialog.isShowing())
            pDialog.show();
    }

    private void hideProgressDialog() {
        if (pDialog.isShowing())
            pDialog.hide();
    }


    /**
     * Making json array request
     */
    private void makeJsonArryReq() {
        showProgressDialog();
        JsonArrayRequest req = new JsonArrayRequest(Const.Marketing_List,
                new Response.Listener<JSONArray>() {
                    @Override
                    public void onResponse(JSONArray response) {
                        Log.d("MYData", response.toString());
                        userCodeList = MarketingCode_JSONParser.parseFeed(response.toString());
                       /* // create an Object for Adapter
                        mAdapter = new UserCodeList_Adapter(userCodeList, StartActivity.this);
                        // set the adapter object to the Recyclerview
                        Search_Recycler.setAdapter(mAdapter);
                        mAdapter.notifyDataSetChanged();
                        //txtTest.setText(response.toString());*/
                        mAdapter.notifyDataSetChanged();
                        hideProgressDialog();
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                VolleyLog.d("Custom Log Error", "Error: " + error.getMessage());
                hideProgressDialog();
            }
        });

        // Adding request to request queue
        AppController.getInstance().addToRequestQueue(req, tag_json_arry);
        // Cancelling request
        // ApplicationController.getInstance().getRequestQueue().cancelAll(tag_json_arry);
    }


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

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

And my adapter :

public class UserCodeList_Adapter extends RecyclerView.Adapter<UserCodeList_Adapter.ViewHolder> {

    private List<Marketing_Code> ucList;
    public static Activity activity;
    public UserCodeList_Adapter(List<Marketing_Code> userCodeList, Activity activity) {
        this.ucList = userCodeList;
        this.activity = activity;
    }
    @Override
    public UserCodeList_Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // create a new view
        View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.listmarketing_cardview, null);

        // create ViewHolder
        ViewHolder viewHolder = new ViewHolder(itemLayoutView);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(UserCodeList_Adapter.ViewHolder viewHolder, int position) {
        String userCode =String.valueOf(ucList.get(position).getMarketCode());
        viewHolder.txtUserID.setText(userCode);
    }

    @Override
    public int getItemCount() {
        return ucList.size();
        //return ucList == null ? 0 : ucList.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {

        public TextView txtUserID;

        public Marketing_Code items;

        public ViewHolder(View itemLayoutView) {
            super(itemLayoutView);

            txtUserID = (TextView) itemLayoutView.findViewById(R.id.txtUserID);
            // Onclick event for the row to show the data in toast
            itemLayoutView.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {
                }
            });

        }

    }
}

4 Answers4

2

You haven't initialized your userCodeList.

Seeing your code, you based your adapter to that list while it is not yet initialized. Consequently, when the adapter tried to learn how much item your list have it throws a NullPointerException.

Change your declaration of userCodeList to one like below:

List<Marketing_Code> userCodeList = new ArrayList<>();

Seeing your updated question, you seem to base your data from a JSON response. If that's the case, what you're currently doing is almost correct.

Observe this slightly modified snippet of your code:

private void makeJsonArryReq() {
    showProgressDialog();
    JsonArrayRequest req = new JsonArrayRequest(Const.Marketing_List,
            new Response.Listener<JSONArray>() {
                @Override
                public void onResponse(JSONArray response) {
                    Log.d("MYData", response.toString());
                    /* YOUR OLD CODE -> */ // userCodeList = MarketingCode_JSONParser.parseFeed(response.toString());
                    /* HOW IT SHOULD'VE BEEN */ userCodeList.addAll(MarketingCode_JSONParser.parseFeed(response.toString()));
                    mAdapter.notifyDataSetChanged();
                    hideProgressDialog();
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            VolleyLog.d("Custom Log Error", "Error: " + error.getMessage());
            hideProgressDialog();
        }
    });

// ...

Look at the commented part of the above snippet. Doing so should solve your problem and make the data visible on screen.

Hadi Satrio
  • 4,272
  • 2
  • 24
  • 45
  • Don't get me any crash now,But my list is empty yet ? –  Aug 02 '16 at 07:54
  • Is this true ? String userCode =String.valueOf(ucList.get(position).getMarketCode()); –  Aug 02 '16 at 07:56
  • Well, it is.. You're supposed to fill that `List` later in the process. Just call `adapter.notifyDataSetChaged()` once you do and you should see your items displayed on screen. – Hadi Satrio Aug 02 '16 at 07:56
  • Where I should use mAdapter.notifyDataSetChanged(); ? –  Aug 02 '16 at 08:02
  • After you fill your `List`.. Where do you source your data from? – Hadi Satrio Aug 02 '16 at 08:02
1

Two ways to handle this:

  1. You need to check if the list is NULL before requesting to check its size

    public int getItemCount () {
        if(ucList == null)
            return 0;
        return ucList.size();
    }
    
  2. Alternatively, and this is the recommended approach to this matter, is to initialise it to an empty list at the start or make sure that it is always initialised before it is accessed by the associated adapter.

    List<Marketing_Code> userCodeList = new ArrayList<>();

Hope this helps.

Hadi Satrio
  • 4,272
  • 2
  • 24
  • 45
batman
  • 1,937
  • 2
  • 22
  • 41
  • The first way might work. But there's no guarantee that it will stop consequent crashes caused by the `null` `List`. Adapters rely heavily on their `List` so it should never be `null` in the first place. – Hadi Satrio Aug 02 '16 at 07:55
  • Agree. Updated answer point 2 to state the recommended approach via initialisation before access – batman Aug 02 '16 at 07:58
0

I think you need to use replaceAll function for the list ,instead of directly equating. Here

 userCodeList = MarketingCode_JSONParser.parseFeed(response.toString());

Try checking if userCodeList contains any data before initialzing the adapter.

Dishonered
  • 8,449
  • 9
  • 37
  • 50
0

Please do the following and try

   // create an Object for Adapter        
    userCodeList = new ArrayList<>();
    mAdapter = new UserCodeList_Adapter(userCodeList, StartActivity.this);
LvN
  • 701
  • 1
  • 6
  • 22