如果没有搜索过城市,刷新面板将永远重新加载

Refresh panel reloads forever if a city hasn't been searched

我在我的天气应用程序上设置了一个滑动刷新面板,以便在我向下滑动刷新按钮时更新我从 API 收到的天气数据。当搜索到一个城市时,此功能可以成功运行,但现在的问题是,如果我在向下滑动刷新面板之前还没有搜索过任何城市,它将永远重新加载,直到我退出应用程序阻碍应用程序进程并且我的应用程序被设计在用户再次搜索城市之前不保存以前的天气数据。

我想完全阻止刷新面板在搜索到一个城市之前重新加载,或者只是限制在搜索到一个城市之前重新加载所需的时间。请问我该怎么做?我检查了这个网站是否有类似的 questions/answers,发现 none helps/relates 与我想要实现的目标相符。

这是当前的刷新面板编程设置:

realSwipe.setOnRefreshListener(() -> {
                // perform the delay action
                new Handler().postDelayed(() -> {
                    // this code is for stop refreshing icon, After 1000 ms automatically refresh icon will stop
                    realSwipe.setRefreshing(false);
                }, 1000);
            });

这是我的片段代码(以备不时之需):

public class FirstFragment extends Fragment {

    private WeatherDataViewModel viewModel;

    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);
        // For displaying weather data
        final TextView current_temp = rootView.findViewById(R.id.textView10);
        final TextView current_output = rootView.findViewById(R.id.textView11);
        final TextView rise_time = rootView.findViewById(R.id.textView25);
        final TextView set_time = rootView.findViewById(R.id.textView26);
        final TextView temp_out = rootView.findViewById(R.id.textView28);
        final TextView Press_out = rootView.findViewById(R.id.textView29);
        final TextView Humid_out = rootView.findViewById(R.id.textView30);
        final TextView Ws_out = rootView.findViewById(R.id.textView33);
        final TextView Visi_out = rootView.findViewById(R.id.textView34);
        final TextView Cloud_out = rootView.findViewById(R.id.textView35);
        final ImageView current_icon = rootView.findViewById(R.id.imageView6);
        final SwipeRefreshLayout realSwipe = rootView.findViewById(R.id.real_swipe);

        // 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.setOnRefreshListener(() -> {
                // perform the delay action
                new Handler().postDelayed(() -> {
                    // this code is for stop refreshing icon, After 1000 ms automatically refresh icon will stop
                    realSwipe.setRefreshing(false);
                }, 1000);
            });

            int drawableResource = -1; // here define default icon for example R.drawable.default_weather_icon

            int soundResource = -1; // Default sound is nothing

            if (data != null) {
                current_temp.setVisibility(View.VISIBLE);
                current_temp.setText(data.getMain().getTemp() + " ℃"); // for that you can use strings resource and templates more in https://developer.android.com/guide/topics/resources/string-resource.html#formatting-strings
                current_output.setVisibility(View.VISIBLE);
                current_output.setText(data.getWeather().get(0).getDescription());
                rise_time.setVisibility(View.VISIBLE);
                rise_time.setText(data.getSys().getSunrise() + " ");
                set_time.setVisibility(View.VISIBLE);
                set_time.setText(data.getSys().getSunset() + " ");
                temp_out.setVisibility(View.VISIBLE);
                temp_out.setText(data.getMain().getTemp() + " ℃");
                Press_out.setVisibility(View.VISIBLE);
                Press_out.setText(data.getMain().getPressure() + " hpa");
                Humid_out.setVisibility(View.VISIBLE);
                Humid_out.setText(data.getMain().getHumidity() + " %");
                Ws_out.setVisibility(View.VISIBLE);
                Ws_out.setText(data.getWind().getSpeed() + " Km/h");
                Visi_out.setVisibility(View.VISIBLE);
                Visi_out.setText(data.getVisibility() + " m");
                Cloud_out.setVisibility(View.VISIBLE);
                Cloud_out.setText(data.getClouds().getAll() + " %");

                // get actual weather.

                String icon = data.getWeather().get(0).getIcon();

                switch (icon) {
                    case "01d":
                    case "01n":
                        drawableResource = R.drawable.sun;
                        soundResource = R.raw.clear_sky_sound;
                        break;

                    case "02d":
                    case "021n":
                        drawableResource = R.drawable.few_clouds;
                        soundResource = R.raw.clouds_sound;
                        break;

                    case "03d":
                    case "03n":
                        drawableResource = R.drawable.scattered_clouds;
                        soundResource = R.raw.clouds_sound;
                        break;

                    case "04d":
                    case "04n":
                        drawableResource = R.drawable.broken_clouds;
                        soundResource = R.raw.clouds_sound;
                        break;

                    case "09d":
                    case "09n":
                        drawableResource = R.drawable.shower_rain;
                        soundResource = R.raw.shower_rain_sound;
                        break;

                    case "10d":
                    case "10n":
                        drawableResource = R.drawable.small_rain;
                        soundResource = R.raw.shower_rain_sound;
                        break;

                    case "11d":
                    case "11n":
                        drawableResource = R.drawable.thunderstorm;
                        soundResource = R.raw.thunderstorm_sound;
                        break;

                    case "13d":
                    case "13n":
                        drawableResource = R.drawable.snow;
                        soundResource = R.raw.snow_sound;
                        break;

                    case "50d":
                    case "50n":
                        drawableResource = R.drawable.mist;
                        soundResource = R.raw.mist_sound;
                        break;
                }

                if (drawableResource != -1)
                    current_icon.setImageResource(drawableResource);
                    // set the first host instance for displaying the weather icons

                if (soundResource != -1 && viewModel.soundResource != soundResource) {
                    viewModel.soundResource = soundResource;
                    if (viewModel.getMediaPlayer() != null) {
                        // we set our soundplayer in retrospect to our viewmodel

                        // stop the playing
                        if (viewModel.getMediaPlayer().isPlaying()) {
                            viewModel.getMediaPlayer().stop();
                        }

                        // release mMediaPlayer resoruces
                        viewModel.getMediaPlayer().release();
                        viewModel.setMediaPlayer(null);
                    }

                    // Play the new resource
                    viewModel.prepareMediaPlayer(requireContext(), soundResource);

                }

            } else {
                Log.e("TAG", "No City found");
                current_temp.setVisibility(View.GONE);
                current_output.setVisibility(View.GONE);
                rise_time.setVisibility(View.GONE);
                set_time.setVisibility(View.GONE);
                temp_out.setVisibility(View.GONE);
                Press_out.setVisibility(View.GONE);
                Humid_out.setVisibility(View.GONE);
                Ws_out.setVisibility(View.GONE);
                Visi_out.setVisibility(View.GONE);
                Cloud_out.setVisibility(View.GONE);
                Toast.makeText(requireActivity(), "No City found", Toast.LENGTH_SHORT).show();
            }
        });

        return rootView;
    }

    public void getWeatherData(String name) {
// The ViewModel controls loading the data, so we just
// tell it what the new name is - this kicks off loading
// the data, which will automatically call through to
// our observe() call when the data load completes
        viewModel.setCityName(name);
    }
}

the problem now is that if I haven't yet searched any city before swiping down the refresh panel, it reloads forever

所以,只要搜索到的城市是blank/empty字符串,就会出现问题。这意味着在这种情况下会触发观察到的 MutuableLiveData 回调。

因为我参与了你的;您在不检查空字符串的情况下加载数据:

private void loadData() {
    // Get the last name that was set
    String name = state.get("name");

    // Now kick off a load from the server
    ApiInterface apiInterface = ApiClient.getClient().create(ApiInterface.class);

    Call<Example> call = apiInterface.getWeatherData(name);

    call.enqueue(new Callback<Example>() {
        @Override
        public void onResponse(@NonNull Call<Example> call, @NonNull Response<Example> response) {
            // Save the response we've gotten
            // This will automatically update our UI
            mutableWeatherData.setValue(response.body());
        }

        @Override
        public void onFailure(@NotNull Call<Example> call, @NotNull Throwable t) {
            t.printStackTrace();
        }
    });
}

解决这个问题:

  • Return如果城市名称为空则早
  • 在更新 UI.
  • 之前检查 API Retrofit 是否没有响应
private void loadData() {
    // Get the last name that was set
    String name = state.get("name");
    
    // Return early if the city name is empty
    if (name == null || name.isEmpty()) return;

    // Now kick off a load from the server
    ApiInterface apiInterface = ApiClient.getClient().create(ApiInterface.class);

    Call<Example> call = apiInterface.getWeatherData(name);

    call.enqueue(new Callback<Example>() {
        @Override
        public void onResponse(@NonNull Call<Example> call, @NonNull Response<Example> response) {
        
            // Check if there is no response from the the Retrofit before updating the UI
            if (response.body() == null) return;
        
            // Save the response we've gotten
            // This will automatically update our UI
            mutableWeatherData.setValue(response.body());
        }

        @Override
        public void onFailure(@NotNull Call<Example> call, @NotNull Throwable t) {
            t.printStackTrace();
        }
    });
}

更新

正如评论和聊天中指出的那样,期望的行为不是定期更新 UI,而是让用户从顶部滑动屏幕来更新 UI.

要解决 swipeToRefresh 重新加载问题,需要从 LiveData 观察中获取 swipeToRefresh 侦听器:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
                         
    // Code is omitted  ....                 
                         
     realSwipe.setOnRefreshListener(() -> {
        // perform the delay action
        new Handler().postDelayed(() -> {
            // this code is for stop refreshing icon, After 1000 ms automatically refresh icon will stop
            realSwipe.setRefreshing(false);
        }, 1000);
    });

    // And whenever the data changes, refresh the UI
    viewModel.getWeatherDataLiveData().observe(getViewLifecycleOwner(), data -> {

        int drawableResource = -1; // here define default icon for example R.drawable.default_weather_icon

        int soundResource = -1; // Default sound is nothing
        
        // Rest of the code ....