0

So I've set up my RecyclerView with SQLite DB and it's populating the list, but every time I click on the list item it should open the new activity and pass data to it via intent extras.

The click gives me NullPointerException:

Process: com.daroioradecic.fxtodo, PID: 6762
     java.lang.NullPointerException: Attempt to invoke interface method 'void data.RecAdapter$ItemClickCallback.onItemClick(int)' on a null object reference
     at data.RecAdapter$RecHolder.onClick(RecAdapter.java:106)
     at android.view.View.performClick(View.java:4856)
     at android.view.View$PerformClick.run(View.java:19956)
     at android.os.Handler.handleCallback(Handler.java:739)
     at android.os.Handler.dispatchMessage(Handler.java:95)
     at android.os.Looper.loop(Looper.java:211)
     at android.app.ActivityThread.main(ActivityThread.java:5389)
     at java.lang.reflect.Method.invoke(Native Method)
     at java.lang.reflect.Method.invoke(Method.java:372)
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1020)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:815)

in my Recycler View adapter class which is:

public class RecAdapter extends RecyclerView.Adapter<RecAdapter.RecHolder> {

    private int previousPosition = 0;

    private List<Todo> listData;
    private LayoutInflater inflater;

    private ItemClickCallback itemClickCallback;


    public interface ItemClickCallback {
        void onItemClick(int p);
    }


    public void setItemClickCallback(final ItemClickCallback itemClickCallback) {
        this.itemClickCallback = itemClickCallback;
    }


    public RecAdapter(List<Todo> listData, Context c) {
        this.inflater = LayoutInflater.from(c);
        this.listData = listData;
    }


    @Override
    public RecHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = inflater.inflate(R.layout.layout_row_za_listu, parent, false);
        return new RecHolder(view);
    }

    @Override
    public void onBindViewHolder(RecHolder holder, int position) {
        Todo item = listData.get(position);
        holder.title.setText(item.getTitle());

        if (position > previousPosition) {
            AnimationUtil.animate(holder, true);
        } else {
            AnimationUtil.animate(holder, false);
        }
        previousPosition = position;

    }

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


    public void setListData(ArrayList<Todo> exerciseList) {
        this.listData.clear();
        this.listData.addAll(exerciseList);
    }


    class RecHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        private TextView title;
        private View container;

        public RecHolder(View itemView) {
            super(itemView);
            title = (TextView) itemView.findViewById(R.id.tekstNaListi);
            container = itemView.findViewById(R.id.cont_item_root);
            container.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            itemClickCallback.onItemClick(getAdapterPosition());

        }
    }


}

It gives the error on line itemClickCallback.onItemClick(getAdapterPosition()); which is the last line in the class.

I'm overriding onClick in the class where recycler view is populated like this:

  @Override
    public void onItemClick(int p) {

        Todo item = (Todo) listData.get(p);
        Intent i = new Intent(HomeScreen.this, Details.class);
        Bundle extras = new Bundle();
        extras.putString("naslov", item.getTitle());
        extras.putString("datum", item.getRecordDate());
        extras.putInt("id", item.getItemId());

        startActivity(i);
    }

That class implements implements RecAdapter.ItemClickCallback

Any ideas? Thanks!

MAIN ACTIVITY CLASS: (keep in mind that I just transitioned from ListView so I haven't done any cleaning)

public class HomeScreen extends AppCompatActivity implements RecAdapter.ItemClickCallback {

    private RecyclerViewUtils.ShowHideToolbarOnScrollingListener showHideToolbarListener;


    //SCROLL
    private Toolbar tToolbar;


    // REC
    private RecyclerView recView;
    private RecAdapter adapter;
    private ArrayList listData;

    // ZA SNACKBAR
    private CoordinatorLayout coordinatorLayout;
    private RelativeLayout relLay;

    // NAVIGACIJA
    private DrawerLayout mDrawer;
    private ActionBarDrawerToggle drawerToggle;
    private Toolbar toolbar;
    NavigationView nvDrawer;
    DrawerLayout dlDrawer;
    //----------------------------------------------------------------------------------------------


    DatabaseHandler dba;
    private ArrayList<Todo> dbTodo = new ArrayList<>();
    private TodoAdapter todoAdapter;
    private ListView lista;
    private Cursor mCursor;

    LinearLayout layoutZaUnosTodoa;
    EditText editTextZaNazivTodoa;
    Button buttonSave;

    private CheckBox checkBoxDoneOrNotNaListi;


    android.support.design.widget.FloatingActionButton fab;

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
        setContentView(R.layout.activity_home_screen);


        tToolbar = (Toolbar) findViewById(R.id.tToolbar);
        setSupportActionBar(tToolbar);
        tToolbar.setNavigationIcon(R.drawable.ic_nav_menu);
        getSupportActionBar().setTitle(R.string.app_name);

        // REC
        recView = (RecyclerView) findViewById(R.id.rec_list);
        recView.setLayoutManager(new LinearLayoutManager(this));
        adapter = new RecAdapter(listData, this);
        recView.setAdapter(adapter);
        adapter.setItemClickCallback(this);

        recView.addOnScrollListener(showHideToolbarListener = new RecyclerViewUtils.ShowHideToolbarOnScrollingListener(tToolbar));

        if (savedInstanceState != null) {
            showHideToolbarListener.onRestoreInstanceState((RecyclerViewUtils.ShowHideToolbarOnScrollingListener.State) savedInstanceState
                    .getParcelable(RecyclerViewUtils.ShowHideToolbarOnScrollingListener.SHOW_HIDE_TOOLBAR_LISTENER_STATE));
        }


        layoutZaUnosTodoa = (LinearLayout) findViewById(R.id.layoutZaUnosTodoa);
        editTextZaNazivTodoa = (EditText) findViewById(R.id.editTextZaNazivTodoa);
        editTextZaNazivTodoa.setSelection(editTextZaNazivTodoa.getText().length());
        buttonSave = (Button) findViewById(R.id.buttonSave);
        //lista = (ListView) findViewById(R.id.lista);
        fab = (android.support.design.widget.FloatingActionButton) findViewById(R.id.fab);
        checkBoxDoneOrNotNaListi = (CheckBox) findViewById(R.id.checkBoxDoneOrNotNaListi);

        coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordiantorLayout);
        relLay = (RelativeLayout) findViewById(R.id.relLay);

        refreshData();

        layoutZaUnosTodoa.setVisibility(View.GONE);


        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                layoutZaUnosTodoa.setVisibility(View.VISIBLE);
            }
        });

        buttonSave.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                saveToDB();
                layoutZaUnosTodoa.setVisibility(View.GONE);
            }
        });

        relLay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                layoutZaUnosTodoa.setVisibility(View.GONE);
            }
        });


        dlDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawerToggle = setupDrawerToggle();

        dlDrawer.setDrawerListener((DrawerLayout.DrawerListener) drawerToggle);


        mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        nvDrawer = (NavigationView) findViewById(R.id.nvView);
        setupDrawerContent(nvDrawer);
        drawerToggle.syncState();


    }


    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putParcelable(RecyclerViewUtils.ShowHideToolbarOnScrollingListener.SHOW_HIDE_TOOLBAR_LISTENER_STATE,
                showHideToolbarListener.onSaveInstanceState());
        super.onSaveInstanceState(outState);
    }

    private void saveToDB() {
        Todo todo = new Todo();
        todo.setTitle(editTextZaNazivTodoa.getText().toString());
        dba.addTodo(todo);
        adapter.notifyDataSetChanged();
        dba.close();
        editTextZaNazivTodoa.setText("");
    }


    public void refreshData() {
        dbTodo.clear();
        dba = new DatabaseHandler(HomeScreen.this);
        ArrayList<Todo> todoFromDB = dba.getTodo();

        for (int i = 0; i < todoFromDB.size(); i++) {
            String title = todoFromDB.get(i).getTitle();
            String dateText = todoFromDB.get(i).getRecordDate();
            int mid = todoFromDB.get(i).getItemId();

            Todo myTodo = new Todo();
            myTodo.setTitle(title);
            myTodo.setItemId(mid);
            myTodo.setRecordDate(dateText);

            dbTodo.add(myTodo);
        }
        dba.close();
        adapter = new RecAdapter(dbTodo, this);
        recView.setAdapter(adapter);

        // todoAdapter = new TodoAdapter(HomeScreen.this, R.layout.layout_row_za_listu, dbTodo);
        //Animation collapseList = AnimationUtils.loadAnimation(HomeScreen.this, R.anim.collapse_search_results);
        //lista.startAnimation(collapseList);
        //lista.setAdapter(todoAdapter);
        // todoAdapter.notifyDataSetChanged();
    }

    @Override
    public void onItemClick(int p) {

        Todo item = (Todo) listData.get(p);
        Intent i = new Intent(HomeScreen.this, Details.class);
        Bundle extras = new Bundle();
        extras.putString("naslov", item.getTitle());
        extras.putString("datum", item.getRecordDate());
        extras.putInt("id", item.getItemId());

        startActivity(i);
    }

   /* @Override
    public void onSecondaryItemClick(int p) {

    }*/


    public class TodoAdapter extends ArrayAdapter<Todo> {
        Activity activity;
        int layoutResource;
        Todo todo;
        ArrayList<Todo> mData = new ArrayList<>();

        public TodoAdapter(Activity act, int resource, ArrayList<Todo> data) {
            super(act, resource, data);
            activity = act;
            layoutResource = resource;
            mData = data;
            notifyDataSetChanged();
        }

        @Override
        public int getCount() {
            return mData.size();
        }

        @Override
        public Todo getItem(int position) {
            return mData.get(position);
        }

        @Override
        public int getPosition(Todo item) {
            return super.getPosition(item);
        }

        @Override
        public long getItemId(int position) {
            return super.getItemId(position);
        }

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

            if (row == null || (row.getTag() == null)) {
                LayoutInflater inflater = LayoutInflater.from(activity);
                row = inflater.inflate(layoutResource, null);
                holder = new ViewHolder();

                holder.mTitle = (TextView) row.findViewById(R.id.tekstNaListi);
                holder.checkBox = (CheckBox) row.findViewById(R.id.checkBoxDoneOrNotNaListi);


                row.setTag(holder);
            } else {
                holder = (ViewHolder) row.getTag();
            }

            holder.myTodo = getItem(position);
            holder.mTitle.setText(holder.myTodo.getTitle());

            final ViewHolder finalHolder = holder;
            holder.mTitle.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    int mid = finalHolder.myTodo.getItemId();
                    DatabaseHandler dba = new DatabaseHandler(HomeScreen.this);
                    dba.deleteTodo(mid);
                    Snackbar snackbar = Snackbar.make(coordinatorLayout, getResources().getString(R.string.snack_bar_tekst), Snackbar.LENGTH_SHORT);
                    snackbar.show();
                    todoAdapter.notifyDataSetChanged();

                    return true;
                }
            });

            /*holder.mTitle.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    String title = finalHolder.myTodo.getTitle().toString();
                    String dateText = finalHolder.myTodo.getRecordDate().toString();
                    int mid = finalHolder.myTodo.getItemId();

                    Intent i = new Intent(HomeScreen.this, Details.class);
                    i.putExtra("naslov", title);
                    i.putExtra("datum", dateText);
                    i.putExtra("id", mid);

                    startActivity(i);
                }
            });*/

            final View finalRow = row;
            holder.checkBox.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    finalHolder.mTitle = (TextView) finalRow.findViewById(R.id.tekstNaListi);

                    if (finalHolder.checkBox.isChecked()) {
                        finalHolder.mTitle.setPaintFlags(finalHolder.mTitle.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
                        finalHolder.mTitle.setAlpha(0.5f);
                    } else if (!finalHolder.checkBox.isChecked()) {
                        finalHolder.mTitle.setPaintFlags(0);
                        finalHolder.mTitle.setAlpha(0.8f);
                    }

                }
            });


            return row;
        }
    }


    class ViewHolder {

        Todo myTodo;
        TextView mTitle, mContent, mDate;
        int mId;
        CheckBox checkBox;
    }

EDIT:

This error shows up:

java.lang.NullPointerException: Attempt to invoke interface method 'void data.RecAdapter$ItemClickCallback.onItemClick(int)' on a null object reference
                                                                            at data.RecAdapter$1.onClick(RecAdapter.java:67)

and it refeers to this line in adapter class:

itemClickCallback.onItemClick(position);
DaxHR
  • 683
  • 1
  • 11
  • 30
  • 1
    did you call `setItemClickCallback` in your code? – Shayan Pourvatan Jun 02 '16 at 20:07
  • Yes in my adapter in onCreate adapter.setItemClickCallback(this); – DaxHR Jun 02 '16 at 20:08
  • can you share those code too. – Shayan Pourvatan Jun 02 '16 at 20:10
  • It's in the first post, but note the text in () – DaxHR Jun 02 '16 at 20:12
  • 1
    in `refreshData` you create new instance of adapter, when you create new instance all data will be reset, don't create new instance and just refresh your data and call notifyDataSetChange or call `setItemClickCallback` for new adapter object. I prefer first approach ( change data ) – Shayan Pourvatan Jun 02 '16 at 20:14
  • If I dont create new instance I get java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference at data.RecAdapter.getItemCount(RecAdapter.java:67) and line 67 is return listData.size(); – DaxHR Jun 02 '16 at 20:21
  • because listData is null, you need change data of your adapter, create method to set new data in adapter. change getCount method to `listData == null ? 0 : listData.size();` as you send null for listData. if this approach is hard to you just call `setItemClickCallback` in `refreshData` method too – Shayan Pourvatan Jun 02 '16 at 20:25

1 Answers1

0

1) Check the callback null or not.

@Override
    public void onClick(View v) {

        if (itemClickCallback!=null){
        itemClickCallback.onItemClick(getAdapterPosition());
        }

    }

2) The activity/class implements the method. This is okay. But, are you set the listener in your onCreate() ?

rectAdapter.setItemClickCallback(this);

3)EDITED Change your adapter like this:

public class RecAdapter extends RecyclerView.Adapter<RecAdapter.RecHolder> {

    private int previousPosition = 0;

    private List<Todo> listData;
    private LayoutInflater inflater;

    private ItemClickCallback itemClickCallback;


    public interface ItemClickCallback {
        void onItemClick(int p);
    }


    public void setItemClickCallback(final ItemClickCallback itemClickCallback) {
        this.itemClickCallback = itemClickCallback;
    }


    public RecAdapter(List<Todo> listData, Context c) {
        this.inflater = LayoutInflater.from(c);
        this.listData = listData;
    }


    @Override
    public RecHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = inflater.inflate(R.layout.layout_row_za_listu, parent, false);
        return new RecHolder(view);
    }

    @Override
    public void onBindViewHolder(RecHolder holder, final int position) {
        Todo item = listData.get(position);
        holder.title.setText(item.getTitle());

        if (position > previousPosition) {
            AnimationUtil.animate(holder, true);
        } else {
            AnimationUtil.animate(holder, false);
        }
        previousPosition = position;

        holder.container.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                itemClickCallback.onItemClick(position);
            }
        });
    }

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


    public void setListData(ArrayList<Todo> exerciseList) {
        this.listData.clear();
        this.listData.addAll(exerciseList);
    }


    class RecHolder extends RecyclerView.ViewHolder {
        private TextView title;
        private View container;

        public RecHolder(View itemView) {
            super(itemView);
            title = (TextView) itemView.findViewById(R.id.tekstNaListi);
            container = itemView.findViewById(R.id.cont_item_root);
        }
   }}
eralp
  • 113
  • 7
  • As it looks like it is null, because now nothing happens on click. I'm setting the listener with this adapter.setItemClickCallback(this); – DaxHR Jun 02 '16 at 20:17
  • Set your click listener itemClickCallback.onItemClick(getAdapterPosition()); into onBindViewHolder and set it with 'position' instead of getAdapterPosition() . – eralp Jun 02 '16 at 20:29
  • OK, so I did as you said and now I'm getting NullPointer at onItemClick() in the activity where recycler is populated: `public void onItemClick(int p) { Todo item = (Todo) listData.get(p); Intent i = new Intent(HomeScreen.this, Details.class); Bundle extras = new Bundle(); extras.putString("naslov", item.getTitle()); extras.putString("datum", item.getRecordDate()); extras.putInt("id", item.getItemId()); startActivity(i); }` and on the line `itemClickCallback.onItemClick(position);` in adapter – DaxHR Jun 02 '16 at 20:59
  • please your edited code in post – eralp Jun 02 '16 at 21:20
  • I updated the post with latest error – DaxHR Jun 02 '16 at 21:24
  • itemClickCallback still looks null? the problem is in your activity. In your activity try to make not class implement type. Try like in adapter. – eralp Jun 03 '16 at 09:21