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

Android底部导航切换时Fragment重复调用Retrofit API问题求助

解决方案:避免Fragment切换时重复调用API

方法1:使用ViewModel托管API请求(推荐)

把API请求逻辑绑定到ViewModel中,利用ViewModel与Activity生命周期绑定的特性,确保API仅在首次触发时请求一次,后续切换Fragment直接复用缓存数据:

实现代码

// 自定义ViewModel类
public class MainViewModel extends ViewModel {
    private MutableLiveData<List<DataModel>> dataLiveData;
    private ApiService apiService;
    private boolean isRequestInitiated = false;

    public MainViewModel() {
        apiService = RetrofitClient.getInstance().getApiService();
        dataLiveData = new MutableLiveData<>();
    }

    public LiveData<List<DataModel>> getData() {
        // 仅在未发起过请求且无缓存数据时调用API
        if (!isRequestInitiated && dataLiveData.getValue() == null) {
            fetchData();
        }
        return dataLiveData;
    }

    private void fetchData() {
        isRequestInitiated = true;
        apiService.fetchData().enqueue(new Callback<List<DataModel>>() {
            @Override
            public void onResponse(Call<List<DataModel>> call, Response<List<DataModel>> response) {
                if (response.isSuccessful()) {
                    dataLiveData.postValue(response.body());
                }
            }

            @Override
            public void onFailure(Call<List<DataModel>> call, Throwable t) {
                // 请求失败时重置标记,允许用户重试
                isRequestInitiated = false;
            }
        });
    }
}

在Fragment中调用:

public class HomeFragment extends Fragment {
    private MainViewModel viewModel;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 获取与宿主Activity绑定的ViewModel实例
        viewModel = new ViewModelProvider(requireActivity()).get(MainViewModel.class);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_home, container, false);
        // 观察数据变化更新UI
        viewModel.getData().observe(getViewLifecycleOwner(), data -> {
            // 这里写UI更新逻辑
        });
        return view;
    }
}

方法2:在Fragment内添加请求标记位

如果不想引入ViewModel,可在Fragment内部添加布尔标记,控制仅首次加载时调用API:

public class HomeFragment extends Fragment {
    private boolean isDataLoaded = false;
    private ApiService apiService;

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        apiService = RetrofitClient.getInstance().getApiService();
        
        // 仅未加载过数据时发起请求
        if (!isDataLoaded) {
            fetchData();
            isDataLoaded = true;
        }
    }

    private void fetchData() {
        apiService.fetchData().enqueue(new Callback<List<DataModel>>() {
            @Override
            public void onResponse(Call<List<DataModel>> call, Response<List<DataModel>> response) {
                if (response.isSuccessful()) {
                    // 更新UI
                }
            }

            @Override
            public void onFailure(Call<List<DataModel>> call, Throwable t) {
                // 请求失败重置标记,允许重试
                isDataLoaded = false;
            }
        });
    }

    // 保存标记状态,避免屏幕旋转等场景下重复请求
    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean("isDataLoaded", isDataLoaded);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null) {
            isDataLoaded = savedInstanceState.getBoolean("isDataLoaded");
        }
    }
}

方法3:优化底部导航的Fragment复用逻辑

默认底部导航切换会销毁重建Fragment,可改为复用已创建的实例,从根源避免重复触发生命周期方法:

public class MainActivity extends AppCompatActivity {
    private Fragment currentFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        BottomNavigationView navView = findViewById(R.id.nav_view);
        navView.setOnItemSelectedListener(item -> {
            Fragment fragment = null;
            String tag = "";
            switch (item.getItemId()) {
                case R.id.navigation_home:
                    tag = "home_fragment";
                    // 先查找已存在的Fragment实例
                    fragment = getSupportFragmentManager().findFragmentByTag(tag);
                    if (fragment == null) {
                        fragment = new HomeFragment();
                    }
                    break;
                // 其他导航项同理处理
            }
            if (fragment != null && fragment != currentFragment) {
                getSupportFragmentManager().beginTransaction()
                        .replace(R.id.nav_host_fragment, fragment, tag)
                        .commit();
                currentFragment = fragment;
            }
            return true;
        });
        
        // 初始化默认显示的Fragment
        if (savedInstanceState == null) {
            navView.setSelectedItemId(R.id.navigation_home);
        }
    }
}

内容的提问来源于stack exchange,提问作者Md Mushaddek Al Mubdi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 23:40:23