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

如何将OpenWeatherMap五日天气预报API返回的JSON数据拆分为按日分组数组?

Hey there! Let's fix that grouping issue for your 5-day weather forecast. The problem with your current cut() method is it just grabs the first 5 entries—which are all within the first 15 hours of the forecast, not 5 distinct days. Here's how to properly group the 3-hour data into daily chunks and adapt it to your ViewPager setup:

Step 1: Create a Daily Weather Data Class

First, let's define a class to hold daily summary data (since each ViewPager page should represent one full day, not a single 3-hour snapshot):

data class DailyWeather(
    val date: String,
    val maxTemp: Double,
    val minTemp: Double,
    val weatherIcon: String,
    val description: String
): java.io.Serializable // Needed for passing via Bundle

Step 2: Replace the cut() Method with Proper Grouping

Update your FiveDaysForecastViewModel to group the 3-hour entries by date, then convert each group into a DailyWeather object. We'll use the dt timestamp (more reliable than string parsing) to get the date:

class FiveDaysForecastViewModel : ViewModel() {
    // Update LiveData type to use our new DailyWeather class
    private val _fiveDaysForecast: MutableLiveData<List<DailyWeather>> = MutableLiveData()
    val fiveDaysForecast: LiveData<List<DailyWeather>> = _fiveDaysForecast

    @ExperimentalSerializationApi
    fun getFiveDaysForecast(cityId: Int) {
        RetrofitClient.api
            .getFiveDaysForecast(cityId = cityId, unit = "metric", lang = "ru")
            .enqueue(object : Callback<FiveDaysForecastResult> {
                override fun onResponse(
                    call: Call<FiveDaysForecastResult>,
                    response: Response<FiveDaysForecastResult>
                ) {
                    if (response.isSuccessful) {
                        response.body()?.let {
                            val dailyWeatherList = it.list.convertToDailyWeather()
                            _fiveDaysForecast.postValue(dailyWeatherList)
                            Timber.d("Successfully grouped daily weather data")
                        }
                    } else {
                        Timber.d("Failed to fetch forecast: ${response.errorBody()?.string()}")
                    }
                }

                override fun onFailure(call: Call<FiveDaysForecastResult>, t: Throwable) {
                    Timber.d("Request failed: ${t.localizedMessage}")
                }
            })
    }

    // Extension function to group 3-hour data into daily summaries
    private fun List<MyList>.convertToDailyWeather(): List<DailyWeather> {
        val dateFormatter = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
        
        return this.groupBy { entry ->
            // Convert timestamp (seconds) to Date, then format to yyyy-MM-dd
            val date = Date(entry.dt * 1000L)
            dateFormatter.format(date)
        }
        .values // Get all entries grouped by date
        .take(5) // Keep only the first 5 days
        .map { dailyEntries ->
            // Calculate daily stats from all 3-hour entries
            val allMainData = dailyEntries.map { it.main }
            val firstWeather = dailyEntries.first().weather.first()
            
            DailyWeather(
                date = dateFormatter.format(Date(dailyEntries.first().dt * 1000L)),
                maxTemp = allMainData.maxOf { it.temp_max },
                minTemp = allMainData.minOf { it.temp_min },
                weatherIcon = firstWeather.icon,
                description = firstWeather.description
            )
        }
    }
}

Step 3: Update the ViewPager Adapter

Modify your PagerAdapter to work with DailyWeather instead of MyList:

class PagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) {
    private var data: List<DailyWeather> = listOf()
    override fun getItemCount() = data.size

    fun submitData(data: List<DailyWeather>) {
        this.data = data
        notifyDataSetChanged()
    }

    override fun createFragment(position: Int): Fragment {
        return if (position in data.indices) {
            DayWeatherFragment().apply {
                arguments = Bundle().apply {
                    putSerializable("TAG", data[position])
                }
            }
        } else Fragment()
    }
}

Step 4: Update the Day Fragment to Display Daily Data

Adjust your DayWeatherFragment to use the DailyWeather data and display meaningful daily info:

class DayWeatherFragment : Fragment() {
    private lateinit var binding: FragmentDayWeatherBinding

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentDayWeatherBinding.inflate(inflater)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val dailyWeather: DailyWeather = arguments?.getSerializable("TAG") as DailyWeather
        
        // Populate your TextViews with daily summary data
        binding.txtDate.text = dailyWeather.date
        binding.txtMaxTemp.text = "Max: ${String.format("%.1f", dailyWeather.maxTemp)}°C"
        binding.txtMinTemp.text = "Min: ${String.format("%.1f", dailyWeather.minTemp)}°C"
        binding.txtWeatherDesc.text = dailyWeather.description.capitalize()
        
        // Optional: Load weather icon using Glide/Picasso
        // Glide.with(this)
        //     .load("https://openweathermap.org/img/w/${dailyWeather.weatherIcon}.png")
        //     .into(binding.imgWeatherIcon)
    }
}

Key Notes

  • We use groupBy with a formatted date to cluster all 3-hour entries into daily groups.
  • For each day, we calculate the max/min temperature from all entries in that day.
  • Using the timestamp (dt) instead of parsing dt_txt makes the code more robust to any format changes in the API response.
  • The DailyWeather class is serializable so we can safely pass it between fragments via a Bundle.

Now your ViewPager will display 5 distinct days of weather, each showing a proper daily summary instead of random 3-hour snapshots!

内容的提问来源于stack exchange,提问作者SoulReaver313

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 11:37:47