RecyclerView跳转Fragment遇空指针及编译错误求助
解决RecyclerView跳转Fragment的空指针及后续编译问题
咱先从你遇到的第一个核心问题——空指针错误说起:Attempt to invoke virtual method 'FragmentManager AppCompatActivity.getSupportFragmentManager()' on a null object reference,根源一目了然,再加上几个小细节问题,咱们一步步把它们修好:
一、先搞定Adapter的空指针问题
看你AlbumAdapter的构造函数,这里直接把自己的null成员变量context赋值给自己了:
public AlbumAdapter(List<Album> albumList) { this.albumList = albumList; this.context = context; // 这里的context本身就是null,等于白赋值! }
这直接导致你在点击事件里调用context.getSupportFragmentManager()时,context是null,触发空指针。另外你还犯了个小错:Fragment fragment = null;之后直接调用fragment.setArguments(bundle),这绝对会触发另一个空指针!
修复步骤:
- 修改Adapter构造函数,正确传入上下文:
private List<Album> albumList; private AppCompatActivity context; public static final String EXTRA_ALBUM_ID = "album_id"; // 改成public,方便Fragment引用 // 给构造函数加个context参数,正确初始化 public AlbumAdapter(AppCompatActivity context, List<Album> albumList) { this.context = context; this.albumList = albumList; }
- 修复点击事件里的Fragment实例化问题:
@Override public void onClick(View v) { int albumId = Math.toIntExact(albumList.get(getAdapterPosition()).safeGetFirstSong().albumId); Log.i(TAG,"INFO - ALBUMADAPTER is passing albumId: "+albumId); FragmentManager fragmentManager = context.getSupportFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); // 必须实例化你的目标Fragment,不能用null! AlbumDetailsFragment fragment = new AlbumDetailsFragment(); Bundle bundle = new Bundle(); bundle.putInt(EXTRA_ALBUM_ID, albumId); fragment.setArguments(bundle); transaction.setCustomAnimations(R.anim.layout_fad_in,R.anim.layout_fad_out, R.anim.layout_fad_in,R.anim.layout_fad_out); // 优化:先拿到当前Fragment再隐藏,避免重复强转context Fragment currentFragment = fragmentManager.findFragmentById(R.id.main_container); if(currentFragment != null){ transaction.hide(currentFragment); } transaction.add(R.id.main_container, fragment); transaction.addToBackStack(null).commit(); }
二、修复目标Fragment的参数获取问题
你的AlbumDetailsFragment在成员变量里直接调用getArguments(),这时候Fragment还没绑定到Activity,getArguments()肯定返回null,分分钟触发空指针:
public class AlbumDetailsFragment extends Fragment{ // 错误时机:Fragment还没初始化,getArguments()返回null Bundle bundle = getArguments(); int s = bundle.getInt("album_id"); }
修复:把参数获取移到Fragment生命周期方法里:
public class AlbumDetailsFragment extends Fragment{ private int albumId; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 这里Fragment已经初始化,getArguments()才有值 if(getArguments() != null){ // 用Adapter里定义的常量,避免硬编码字符串写错 albumId = getArguments().getInt(AlbumAdapter.EXTRA_ALBUM_ID); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { ViewGroup root = (ViewGroup) inflater.inflate(R.layout.album_details_fragment, container, false); // 这里就可以用albumId加载专辑详情了 return root; } }
三、解决后续的编译错误
你修改Adapter构造函数后,调用的地方没传context,所以报错required: AppCompatActivity,List found: List。另外你之前写的new AlbumAdapter(this, ...)里的this是AsyncTask的实例,不是Activity,这也是错的。
修复AlbumFragment里的Adapter初始化:
public class LoadData extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... strings) { if (getActivity() != null) { // 把getActivity()强转成AppCompatActivity传入 albumAdapter = new AlbumAdapter((AppCompatActivity)getActivity(), new AudioLoader().getAllAlbums(getActivity())); // 别忘了在UI线程设置Adapter,因为AsyncTask的doInBackground是后台线程 recyclerView.post(() -> recyclerView.setAdapter(albumAdapter)); } return "Executed"; } }
修复AlbumSongsFragment里的Adapter初始化:
public class LoadData extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... strings) { if(getActivity()!=null) { albumAdapter=new AlbumAdapter((AppCompatActivity)getActivity(), Collections.singletonList(new AudioLoader().getAlbum(getActivity(), albumId))); // 同样要在UI线程设置Adapter recyclerView.post(() -> recyclerView.setAdapter(albumAdapter)); } return "Executed"; } }
额外小建议
- 尽量别在Adapter里直接处理Fragment跳转,推荐用接口回调的方式,让宿主Fragment/Activity来处理跳转,这样解耦性更好,还能避免context持有导致内存泄漏。比如在Adapter里定义一个
OnAlbumItemClickListener接口,在宿主Fragment里实现,然后点击时调用接口方法,由宿主来做Fragment事务。 - 处理Fragment事务时,最好判断一下
context != null和isAdded(),避免Activity已经销毁时触发异常。
内容的提问来源于stack exchange,提问作者Robert Vogl
相关产品推荐
相关产品推荐

