Android开发:Fragment依附MainActivity失败?空对象引用报错求助
解决ViewPager中Fragment空指针问题(Attempt to invoke virtual method on a null object reference)
这个错误的核心原因很明确:你通过findFragmentByTag获取FragmentThree的时候,这个Fragment还没有被ViewPager创建并添加到FragmentManager中,所以返回了null,调用它的方法自然就抛出空指针了。
为什么会出现这种情况?
ViewPager默认有一个offscreenPageLimit属性,默认值是1——意思是它只会预加载当前显示页面的左右各1个Fragment。比如你当前在第0页(FragmentOne),ViewPager只会创建第1页(FragmentTwo),第2页(FragmentThree)要等你滑过去的时候才会初始化。这时候你在FragmentOne里调用方法找第2页的Fragment,肯定找不到。
解决方案一:修改ViewPager的预加载数量(简单直接,适合页面少的场景)
如果你只有3个Fragment,可以直接把预加载数量设为2,让ViewPager一次性创建所有Fragment:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); viewPager = (ViewPager) findViewById(R.id.viewPager); viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager()); viewPager.setAdapter(viewPagerAdapter); // 添加这一行,设置预加载所有3个页面 viewPager.setOffscreenPageLimit(2); tabLayout = (TabLayout) findViewById(R.id.tabs); tabLayout.setupWithViewPager(viewPager); }
这种方法简单,但如果Fragment很多,预加载会占用更多内存,所以只适合页面数量少的情况。
解决方案二:用ViewModel/LiveData传递数据(推荐的组件化方式)
这是Google推荐的Fragment间通信方式,避免直接持有Fragment引用,从根源上解决空指针和内存泄漏问题。
- 首先创建一个共享的ViewModel:
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; public class SharedViewModel extends ViewModel { private final MutableLiveData<String> latLonData = new MutableLiveData<>(); public void setLatLonData(String data) { latLonData.setValue(data); } public MutableLiveData<String> getLatLonData() { return latLonData; } }
- 在FragmentOne中获取ViewModel并发送数据:
// FragmentOne里的sendDataLatLon方法修改为 @Override public void sendDataLatLon(String message) { SharedViewModel viewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class); viewModel.setLatLonData(message); }
- 在FragmentThree中观察数据变化:
public class FragmentThree extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_three, container, false); // 初始化视图... SharedViewModel viewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class); viewModel.getLatLonData().observe(getViewLifecycleOwner(), message -> { // 这里处理收到的数据,相当于原来的displayReceivedDataLanLon方法 displayReceivedDataLanLon(message); }); return view; } public void displayReceivedDataLanLon(String message) { // 你的原有逻辑 } }
这种方式不管Fragment是否已经创建,只要它处于活跃状态就能收到数据,而且完全符合Jetpack组件的设计规范。
解决方案三:在ViewPagerAdapter中保存Fragment实例
如果你不想用ViewModel,也可以在Adapter里维护Fragment的实例,直接通过Adapter获取:
- 修改ViewPagerAdapter:
import java.util.ArrayList; import java.util.List; public class ViewPagerAdapter extends FragmentPagerAdapter { // 保存Fragment实例的列表 private List<Fragment> fragmentList = new ArrayList<>(); public ViewPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { Fragment fragment = null; if (position == 0) { fragment = new FragmentOne(); } else if (position == 1) { fragment = new FragmentTwo(); } else if (position == 2) { fragment = new FragmentThree(); } // 添加到列表中 fragmentList.add(fragment); return fragment; } @Override public int getCount() { return 3; } // 提供获取Fragment的方法 public Fragment getFragment(int position) { return fragmentList.get(position); } }
- 在MainActivity中修改sendDataLatLon方法:
@Override public void sendDataLatLon(String message) { FragmentThree f = (FragmentThree) viewPagerAdapter.getFragment(2); // 这里最好加个判空,避免极端情况(比如Fragment还没初始化) if (f != null && f.isAdded()) { f.displayReceivedDataLanLon(message); } }
这种方式比用tag更可靠,但也要注意判空,因为极端情况下Fragment可能还没完成初始化。
内容的提问来源于stack exchange,提问作者Szarik
相关产品推荐
相关产品推荐

