Search code examples
androidandroid-recyclerviewinterfacenullpointerexceptionadapter

Null Pointer Exception by Invoke Interface between RecyclerView Adapter and Fragment


I'm following approach from Jared Burrows from the post here: How to create interface between Fragment and adapter? Unfortunately I'm getting NPE at line interfacePostAdapter.textMessage(username); I understand that the issue is with interface initialization, but unfortunately I cannot find solution from all similar posts.

My Adapter

public class PostDataAdapter extends RecyclerView.Adapter<PostDataAdapter.ViewHolder> {
    private ArrayList<PostData> arrayList;
    private InterfacePostAdapter interfacePostAdapter;

    public PostDataAdapter(ArrayList<PostData> arrayList, InterfacePostAdapter interfacePostAdapter) {
        this.arrayList = arrayList;
        this.interfacePostAdapter = interfacePostAdapter;
    }


    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_postdata_recyclerview,parent, false);
        ViewHolder viewHolder = new ViewHolder(view,interfacePostAdapter);
        return viewHolder;
    }

    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.name.setText(arrayList.get(position).getName());
    }

    public int getItemCount() {
        return  arrayList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder{
        TextView name;
        ImageView userImg;
        InterfacePostAdapter interfacePostAdapter;
        public ViewHolder(View itemView, InterfacePostAdapter interfacePostAdapter) {
            super(itemView);
            name = itemView.findViewById(R.id.textView_name);
            userImg = itemView.findViewById(R.id.imgView_userIcon);
            this.interfacePostAdapter = interfacePostAdapter;

            userImg.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int position = getBindingAdapterPosition();
                    String username = arrayList.get(position).getName();
                    interfacePostAdapter.textMessage(username);  // here is NullPointerException
                }
            });
        }
    }

    public interface InterfacePostAdapter {
        void textMessage (String username);
    }
}

My Fragment

public class LoggedInFragment extends Fragment implements PostDataAdapter.InterfacePostAdapter {

    private FragmentLoggedinBinding binding;
    private PostDataAdapter postDataAdapter;
    private PostDataViewModel postDataViewModel;
    private RecyclerView recyclerView;
    PostDataAdapter.InterfacePostAdapter interfacePostAdapter;

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_loggedin, container, false);
        View view = binding.getRoot();
        recyclerView = binding.recyclerView;
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        postDataAdapter = new PostDataAdapter(postDataViewModel.getPostData().getValue(), interfacePostAdapter);
        recyclerView.setAdapter(postDataAdapter);
        return view;
    }

    @Override
    public void textMessage(String username) {
        Toast.makeText(getContext(),username, Toast.LENGTH_SHORT).show();
    }

    //This part should be not relevant to the interface issue
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        postDataViewModel = new ViewModelProvider(this).get(PostDataViewModel.class);
        postDataViewModel.initPostData();
        postDataViewModel.getPostData().observe(this, new Observer<ArrayList<PostData>>() {
            @Override
            public void onChanged(ArrayList<PostData> arrayList) {
                postDataAdapter.notifyDataSetChanged();
            }
        });
    }
}

Solution

  • You need to track your variable and make sure it's initialized properly. After doing that, I concluded that you haven't actually given a value to PostDataAdapter.InterfacePostAdapter interfacePostAdapter; in your LoggedInFragment anywhere. I do see that your fragment implements the said interface, so in that case you actually do not need the variable at all, just change that line this:

    postDataAdapter = new PostDataAdapter(postDataViewModel.getPostData().getValue(), interfacePostAdapter);
    

    to this:

    postDataAdapter = new PostDataAdapter(postDataViewModel.getPostData().getValue(), this);
    

    Explanation:

    Your variable was not initialized anywhere, so you were basically passing null to your adapter. There's a couple of ways you can pass an interface, and you mixed two of them in a bad way - when the class implements that interface, you can pass the current instance using this, or you could have used your variable but with proper initialization.