Android天气应用未搜索城市时SwipeRefreshLayout无限刷新如何修复
问题根因
你当前的代码核心问题是将SwipeRefreshLayout的刷新监听器注册逻辑写在了天气数据LiveData的观察回调中,只有当用户搜索过城市、LiveData首次返回数据后,刷新监听器才会被绑定。未搜索城市时下拉刷新,没有对应的停止刷新逻辑,才会出现动画无限加载的情况。另外你原有刷新逻辑只有停止动画的代码,没有实际触发重新请求天气数据的逻辑,下拉刷新功能实际无效。
实现方案
下面分别对应你提出的两个需求给出可直接复用的修改方案:
方案1:未搜索城市前完全禁止下拉刷新(更贴合你的业务逻辑)
修改逻辑:初始化刷新组件时默认禁用下拉功能,首次成功获取到天气数据后再启用刷新权限,同时将刷新监听器从LiveData回调中移到初始化层级,避免重复绑定。
修改后的代码示例:
public class FirstFragment extends Fragment { private WeatherDataViewModel viewModel; // 新增:保存当前搜索的城市名,用于刷新请求 private String currentCityName; public FirstFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View rootView = inflater.inflate(R.layout.fragment_first, container, false); // ... 其他控件初始化代码保持不变 final SwipeRefreshLayout realSwipe = rootView.findViewById(R.id.real_swipe); // 1. 默认禁用下拉刷新 realSwipe.setEnabled(false); // 2. 在此处设置刷新监听器,不要放在LiveData的observe回调内 realSwipe.setOnRefreshListener(() -> { // 触发刷新当前城市的天气数据 viewModel.setCityName(currentCityName); // 增加3秒超时兜底,避免网络请求失败一直显示刷新动画 new Handler().postDelayed(() -> { realSwipe.setRefreshing(false); }, 3000); }); // Get our ViewModel instance viewModel = new ViewModelProvider(requireActivity()).get(WeatherDataViewModel.class); // And whenever the data changes, refresh the UI viewModel.getWeatherDataLiveData().observe(getViewLifecycleOwner(), data -> { // 数据加载完成后首先停止刷新动画 realSwipe.setRefreshing(false); int drawableResource = -1; int soundResource = -1; if (data != null) { // 3. 成功获取到数据后,启用下拉刷新权限 realSwipe.setEnabled(true); // ... 原有数据展示逻辑全部保持不变 } else { Log.e("TAG", "No City found"); // ... 原有无数据提示逻辑全部保持不变 } }); return rootView; } public void getWeatherData(String name) { // 保存当前搜索的城市名 currentCityName = name; viewModel.setCityName(name); } }
方案2:未搜索城市时限制刷新加载时长
不需要禁用下拉,只需要兜底停止刷新动画,直接将刷新监听器移到初始化位置,增加未搜索场景的判断即可:
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // ... 其他初始化代码不变 final SwipeRefreshLayout realSwipe = rootView.findViewById(R.id.real_swipe); realSwipe.setOnRefreshListener(() -> { // 判断是否已搜索过城市 if (currentCityName == null || viewModel.getWeatherDataLiveData().getValue() == null) { // 未搜索场景,1秒后停止刷新并提示 new Handler().postDelayed(() -> { realSwipe.setRefreshing(false); Toast.makeText(requireContext(), "请先搜索城市后再刷新", Toast.LENGTH_SHORT).show(); }, 1000); return; } // 已有城市的正常刷新逻辑 viewModel.setCityName(currentCityName); new Handler().postDelayed(() -> { realSwipe.setRefreshing(false); }, 3000); }); // ... 后续逻辑不变 }
内容的提问来源于stack exchange,提问作者Richard Wilson
相关产品推荐
相关产品推荐

