You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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引用,从根源上解决空指针和内存泄漏问题。

  1. 首先创建一个共享的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;
    }
}
  1. 在FragmentOne中获取ViewModel并发送数据:
// FragmentOne里的sendDataLatLon方法修改为
@Override
public void sendDataLatLon(String message) {
    SharedViewModel viewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
    viewModel.setLatLonData(message);
}
  1. 在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获取:

  1. 修改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);
    }
}
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:17:50