RecyclerView Adapter 和 Fragment 之间调用接口的空指针异常
Null Pointer Exception by Invoke Interface between RecyclerView Adapter and Fragment
我在这里遵循来自 post 的 Jared Burrows 的方法:How to create interface between Fragment and adapter? 不幸的是,我在 interfacePostAdapter.textMessage(username) 行遇到了 NPE;我知道问题出在接口初始化上,但不幸的是我无法从所有类似的 posts.
中找到解决方案
我的适配器
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);
}
}
我的片段
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();
}
});
}
}
您需要跟踪您的变量并确保它已正确初始化。这样做之后,我得出结论,您实际上并没有在 LoggedInFragment
中的任何地方给 PostDataAdapter.InterfacePostAdapter interfacePostAdapter;
赋值。我确实看到你的片段实现了上述接口,所以在那种情况下你实际上 根本不需要 变量,只需将那行更改为:
postDataAdapter = new PostDataAdapter(postDataViewModel.getPostData().getValue(), interfacePostAdapter);
对此:
postDataAdapter = new PostDataAdapter(postDataViewModel.getPostData().getValue(), this);
解释:
你的变量没有在任何地方初始化,所以你基本上是将 null 传递给你的适配器。有几种方法可以传递一个接口,并且你以一种糟糕的方式混合了其中两种 - 当 class 实现该接口时,你可以使用 this
传递当前实例,或者你可以使用了您的变量,但进行了正确的初始化。
我在这里遵循来自 post 的 Jared Burrows 的方法:How to create interface between Fragment and adapter? 不幸的是,我在 interfacePostAdapter.textMessage(username) 行遇到了 NPE;我知道问题出在接口初始化上,但不幸的是我无法从所有类似的 posts.
中找到解决方案我的适配器
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);
}
}
我的片段
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();
}
});
}
}
您需要跟踪您的变量并确保它已正确初始化。这样做之后,我得出结论,您实际上并没有在 LoggedInFragment
中的任何地方给 PostDataAdapter.InterfacePostAdapter interfacePostAdapter;
赋值。我确实看到你的片段实现了上述接口,所以在那种情况下你实际上 根本不需要 变量,只需将那行更改为:
postDataAdapter = new PostDataAdapter(postDataViewModel.getPostData().getValue(), interfacePostAdapter);
对此:
postDataAdapter = new PostDataAdapter(postDataViewModel.getPostData().getValue(), this);
解释:
你的变量没有在任何地方初始化,所以你基本上是将 null 传递给你的适配器。有几种方法可以传递一个接口,并且你以一种糟糕的方式混合了其中两种 - 当 class 实现该接口时,你可以使用 this
传递当前实例,或者你可以使用了您的变量,但进行了正确的初始化。