-2

I am new in Android Development and I am using this code to implement callback between adapter and fragmnet.

BookAdapter

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


    private OnButtonClickListener onButtonClickListener;

    //List of books
    private List<BookItems> mBookItems;

    private final int VIEW_ITEM = 0;
    private final int VIEW_PROG = 1;

    private int lastPosition = -1;

    public void OnButtonClickListener (OnButtonClickListener onButtonClickListener) {
        this.onButtonClickListener = onButtonClickListener;
    }

    public interface OnButtonClickListener {
        void onButtonClick();
    }

   public BookAdapter(List<BookItems> bookItems, Context context) {
       super();

       //Getting all books
       this.mBookItems = bookItems;
       this.mContext = context;
   }


    @Override
    public int getItemViewType(int position) {
        if (isPositionItem(position))
            return VIEW_ITEM;
        return VIEW_PROG;
    }

    private boolean isPositionItem(int position) {
       return position != getItemCount()-1;
    }



    @Override
    public RecyclerView.ViewHolder  onCreateViewHolder (ViewGroup parent, int viewType) {
        if (viewType == VIEW_ITEM) {
            View v =  LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.book_summ, parent, false);
            return new TextViewHolder(v);
        } else if (viewType == VIEW_PROG){
            View v = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.recyclerfooter, parent, false);
            return new ProgressViewHolder(v);
        }

        return null;
    }



    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        if (holder instanceof TextViewHolder) {
            final BookItems bookList = mBookItems.get(position);
            /...

        } else {
            ((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
            ((ProgressViewHolder) holder).loadButton.setText(R.string.reload);
        }


    }

    @Override
    public int getItemCount(){
        //Return the number of items in the data set
        return mBookItems.size();
    }

    public class TextViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        ...
        }


    public  class ProgressViewHolder extends RecyclerView.ViewHolder implements  View.OnClickListener{
        Button loadButton;
        ProgressBar progressBar;
        public ProgressViewHolder(View footerView){
            super(footerView);
           ...
        }

        @Override
        public void onClick(View v) {
            if (v.getId() == loadButton.getId()) {
                        onButtonClickListener.onButtonClick();

            }
        }
    }


}

BookFragment

public class BookFragment extends Fragment implements BookAdapter.OnButtonClickListener{

   
    BookAdapter mAdapter;

    //Creating a list of books
    private List<BookItems> mBookItemsList;

    //Creating Views
    ObservableRecyclerView recyclerView;
    private String title;
    private RecyclerView.Adapter adapter;
    private ProgressDialog mProgressDialog;
    SwipeRefreshLayout mSwipeRefreshLayout;
    LinearLayoutManager mLayoutManager;



    public BookFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAdapter = new BookAdapter(mBookItemsList,getContext());
        mAdapter.OnButtonClickListener(this);
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        title = getArguments().getString("title");
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_book, container, false);

        //Initializing Views
        ...

        return view;
    }

    ... 
    
    @Override
    public void onButtonClick() {
        Log.d(TAG, "I recieved it Sir");
        Toast.makeText(getActivity(), "blag blag", Toast.LENGTH_SHORT).show();
    }
}

Each time I click on loadButton, the app crashes with nullpointer exception. Do you have any idea why this is happening and how I can correct this?


Logcat

05-21 01:34:17.710 20717-20717/com.myapp.bookman E/AndroidRuntime: FATAL EXCEPTION: main
                                                                     Process: com.myapp.bookman, PID: 20717
                                                                     java.lang.NullPointerException: Attempt to invoke interface method 'void com.myapp.bookman.BookAdapter$OnButtonClickListener.onButtonClick()' on a null object reference
                                                                         at com.myapp.bookman.BookAdapter$ProgressViewHolder.onClick(BookAdapter.java:251)
                                                                         at android.view.View.performClick(View.java:5076)
                                                                         at android.view.View$PerformClick.run(View.java:20279)
                                                                         at android.os.Handler.handleCallback(Handler.java:739)
                                                                         at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                         at android.os.Looper.loop(Looper.java:135)
                                                                         at android.app.ActivityThread.main(ActivityThread.java:5910)
                                                                         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:1405)
                                                                         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1200)

In the stacktrace line 251, is line onButtonClickListener.onButtonClick(); in BookAdapter

After Implementing TychoTheTaco answer

BookAdapter

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


    

    //List of books
    private List<BookItems> mBookItems;

    private final int VIEW_ITEM = 0;
    private final int VIEW_PROG = 1;

    private int lastPosition = -1;

    public void OnButtonClickListener (OnButtonClickListener onButtonClickListener) {
        this.onButtonClickListener = onButtonClickListener;
    }

    public interface OnButtonClickListener {
        void onButtonClick();
    }

   public BookAdapter(List<BookItems> bookItems, Context context) {
       super();

       //Getting all books
       this.mBookItems = bookItems;
       this.mContext = context;
   }


    @Override
    public int getItemViewType(int position) {
        if (isPositionItem(position))
            return VIEW_ITEM;
        return VIEW_PROG;
    }

    private boolean isPositionItem(int position) {
       return position != getItemCount()-1;
    }



    @Override
    public RecyclerView.ViewHolder  onCreateViewHolder (ViewGroup parent, int viewType) {
        if (viewType == VIEW_ITEM) {
            View v =  LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.book_summ, parent, false);
            return new TextViewHolder(v);
        } else if (viewType == VIEW_PROG){
            View v = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.recyclerfooter, parent, false);
            return new ProgressViewHolder(v);
        }

        return null;
    }



    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        if (holder instanceof TextViewHolder) {
            final BookItems bookList = mBookItems.get(position);
            /...

        } else {
            ((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
            ((ProgressViewHolder) holder).loadButton.setText(R.string.reload);
        }


    }

    @Override
    public int getItemCount(){
        //Return the number of items in the data set
        return mBookItems.size();
    }

    public class TextViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        ...
        }


    public  class ProgressViewHolder extends RecyclerView.ViewHolder implements  View.OnClickListener{
        Button loadButton;
        ProgressBar progressBar;
        public ProgressViewHolder(View footerView){
            super(footerView);
           ...
        }

        @Override
        public void onClick(View v) {
            if (v.getId() == loadButton.getId()) {
                        onButtonClickListener.onButtonClick();

            }
        }
    }


}

BookFragment

    public class BookFragment extends Fragment implements BookAdapter.OnButtonClickListener{
    
       
        BookAdapter mAdapter;
    
        //Creating a list of books
        private List<BookItems> mBookItemsList;
    
        //Creating Views
        ObservableRecyclerView recyclerView;
        private String title;
        private RecyclerView.Adapter adapter;
        private ProgressDialog mProgressDialog;
        SwipeRefreshLayout mSwipeRefreshLayout;
        LinearLayoutManager mLayoutManager;
    
    
    
        public BookFragment() {
            // Required empty public constructor
        }
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mAdapter = new BookAdapter(mBookItemsList,getContext());
            mAdapter.OnButtonClickListener(this);
        }
    
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            title = getArguments().getString("title");
            // Inflate the layout for this fragment
            View view = inflater.inflate(R.layout.fragment_book, container, false);
    
            //Initializing Views
            ...
    
            return view;
        }
    
        ... 
        OnButtonClickListener onButtonClickListener = new OnButtonClickListener() {
        @Override
        public void onButtonClick() {
            Log.d(TAG, "I recieved it Sir");
            Toast.makeText(getActivity(), "blag blag", Toast.LENGTH_SHORT).show();
        }
    }
}

The problem with this is that onButtonClickListener in line this.onButtonClickListener = onButtonClickListener; in BookAdapter, Android studio is saying "cannot resolve symbol onButtonClickListener"

And also, in BookFragment,in line public class BookFragment extends Fragment implements BookAdapter.OnButtonClickListener I nust either declare the class abstract or implement onButtoClick() in OnButtonClickListener.

Community
  • 1
  • 1
Abdullq
  • 69
  • 1
  • 8
  • Possible duplicate of [What is a Null Pointer Exception, and how do I fix it?](http://stackoverflow.com/questions/218384/what-is-a-null-pointer-exception-and-how-do-i-fix-it) – Vucko May 21 '16 at 01:03
  • @Vucko this is not a duplicate, I know what nullpointer means but I haven't done callbacks between adapter and fragment. Please can you look at the the code more critically? – Abdullq May 21 '16 at 01:08
  • 1
    If you'd post the logcat and specifically point us to the line where NPE occurs, I might. – Vucko May 21 '16 at 01:12
  • @Vucko my bad, I haved added the stacktrace to my question. – Abdullq May 21 '16 at 01:25

1 Answers1

0

You create your private OnButtonClickListener onButtonClickListener; but it is never assigned so when you call onButtonClickListener.onButtonClick(); it gives a NPE.

In BookAdapter, replace

private OnButtonClickListener onButtonClickListener;

with

OnButtonClickListener onButtonClickListener = new OnButtonClickListener(){ @Override public void onButtonClick(){ //Do stuff } };

TychoTheTaco
  • 664
  • 1
  • 7
  • 28
  • Thanks for the reply, got any idea what I should assign it to? I'm lost here. – Abdullq May 21 '16 at 01:30
  • Maybe I'm getting you wrong but `private OnButtonClickListener onButtonClickListener;` is in **BookAdapter** while `@Override public void onButtonClick(){...` is in **BookFragment**. If I remove `private OnButtonClickListener onButtonClickListener;` from **BookAdapter** it shows an error. – Abdullq May 21 '16 at 02:50
  • Can you show your updated code and the error message? – TychoTheTaco May 21 '16 at 03:35
  • In your **BookFragment**, remove the `onButtonClick()`. Then in **BookAdapter** make sure this `public interface OnButtonClickListener { void onButtonClick(); }` is **before** this `OnButtonClickListener onButtonClickListener = new OnButtonClickListener(){ @Override public void onButtonClick(){ //Do stuff } };` – TychoTheTaco May 21 '16 at 22:48