构建基于Android Studio开发天气预报应用

Android Studio开发天气预报应用需要完成API调用、UI设计、数据解析等步骤。以下是基于OpenWeatherMap API的实现方法,包含关键代码片段和详细说明。

环境准备与项目创建构建基于Android Studio开发天气预报应用_第1张图片

确保已安装Android Studio最新版本,创建新项目选择Empty Activity模板。在build.gradle模块文件中添加必要依赖:

dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'com.github.bumptech.glide:glide:4.12.0'
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
}

同步项目后,在AndroidManifest.xml中添加网络权限:


获取OpenWeatherMap API密钥

访问OpenWeatherMap官网注册账号,在个人仪表板获取免费API密钥。免费版每小时可调用60次,支持当前天气和5天预报。

数据模型设计

创建三个数据类对应API响应结构:

data class WeatherResponse(
    val name: String, // 城市名
    val main: MainData,
    val weather: List,
    val dt: Long // 时间戳
)

data class MainData(
    val temp: Double,
    val feels_like: Double,
    val humidity: Int
)

data class WeatherInfo(
    val id: Int,
    val main: String,
    val description: String,
    val icon: String
)

预报数据模型单独建立:

data class ForecastResponse(
    val list: List
)

data class ForecastItem(
    val dt: Long,
    val main: MainData,
    val weather: List
)

网络请求实现

使用Retrofit构建API服务接口:

interface WeatherApiService {
    @GET("weather")
    suspend fun getCurrentWeather(
        @Query("q") city: String,
        @Query("units") units: String = "metric",
        @Query("appid") apiKey: String = "YOUR_API_KEY"
    ): Response

    @GET("forecast")
    suspend fun getForecast(
        @Query("q") city: String,
        @Query("units") units: String = "metric",
        @Query("appid") apiKey: String = "YOUR_API_KEY"
    ): Response
}

创建Retrofit实例:

object RetrofitClient {
    private const val BASE_URL = "https://api.openweathermap.org/data/2.5/"

    val instance: WeatherApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(WeatherApiService::class.java)
    }
}

ViewModel层实现

创建ViewModel处理业务逻辑:

class WeatherViewModel : ViewModel() {
    private val _currentWeather = MutableLiveData()
    val currentWeather: LiveData = _currentWeather

    private val _forecast = MutableLiveData>()
    val forecast: LiveData> = _forecast

    suspend fun fetchWeatherData(city: String) {
        viewModelScope.launch {
            try {
                val currentResponse = RetrofitClient.instance.getCurrentWeather(city)
                if (currentResponse.isSuccessful) {
                    _currentWeather.postValue(currentResponse.body())
                }

                val forecastResponse = RetrofitClient.instance.getForecast(city)
                if (forecastResponse.isSuccessful) {
                    _forecast.postValue(forecastResponse.body()?.list?.take(8)) // 取未来24小时预报
                }
            } catch (e: Exception) {
                // 错误处理
            }
        }
    }
}

UI界面设计

activity_main.xml布局文件包含搜索框和天气显示区域:



    

    

    

    

    

创建预报项的RecyclerView布局item_forecast.xml


    
    
    

数据绑定与显示

在主Activity中实现数据观察和绑定:

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: WeatherViewModel
    private lateinit var forecastAdapter: ForecastAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        viewModel = ViewModelProvider(this).get(WeatherViewModel::class.java)
        setupRecyclerView()
        setupObservers()
        setupSearchView()
    }

    private fun setupRecyclerView() {
        forecastRecyclerView.layoutManager = LinearLayoutManager(this, HORIZONTAL, false)
        forecastAdapter = ForecastAdapter()
        forecastRecyclerView.adapter = forecastAdapter
    }

    private fun setupObservers() {
        viewModel.currentWeather.observe(this) { weather ->
            temperatureText.text = "${weather.main.temp}°C"
            descriptionText.text = weather.weather[0].description
            Glide.with(this)
                .load("https://openweathermap.org/img/wn/${weather.weather[0].icon}@2x.png")
                .into(weatherIcon)
        }

        viewModel.forecast.observe(this) { items ->
            forecastAdapter.submitList(items)
        }
    }

    private fun setupSearchView() {
        searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(query: String): Boolean {
                lifecycleScope.launch {
                    viewModel.fetchWeatherData(query)
                }
                return true
            }
            //...其他方法
        })
    }
}

预报列表适配器实现

创建RecyclerView适配器显示预报数据: 

class ForecastAdapter : ListAdapter(DiffCallback()) {

    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val timeText: TextView = view.findViewById(R.id.timeText)
        val icon: ImageView = view.findViewById(R.id.forecastIcon)
        val tempText: TextView = view.findViewById(R.id.forecastTempText)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_forecast, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = getItem(position)
        holder.timeText.text = SimpleDateFormat("HH:mm", Locale.getDefault())
            .format(Date(item.dt * 1000))
        holder.tempText.text = "${item.main.temp}°C"
        Glide.with(holder.itemView)
            .load("https://openweathermap.org/img/wn/${item.weather[0].icon}.png")
            .into(holder.icon)
    }

    class DiffCallback : DiffUtil.ItemCallback() {
        override fun areItemsTheSame(oldItem: ForecastItem, newItem: ForecastItem) = oldItem.dt == newItem.dt
        override fun areContentsTheSame(oldItem: ForecastItem, newItem: ForecastItem) = oldItem == newItem
    }
}

功能扩展建议 

  1. 位置服务:添加GPS定位获取当前位置天气
  2. 天气预警:集成极端天气警报通知功能
  3. 数据缓存:使用Room数据库实现离线访问
  4. 主题切换:根据天气状况动态改变应用主题色
  5. 多语言支持:适配不同语言的天气描述

常见问题解决 

API返回401错误:检查API密钥是否正确,确保已激活OpenWeatherMap服务

图片加载失败:验证Glide初始化,检查网络权限

数据不更新:确认LiveData观察者已正确注册,检查网络请求是否成功

内存泄漏:在onDestroy中取消所有协程,避免持有Activity引用

通过以上步骤可构建完整的天气预报应用,实际开发中建议添加加载状态提示和错误处理机制提升用户体验。记得将YOUR_API_KEY替换为实际获得的OpenWeatherMap API密钥。

你可能感兴趣的:(Android,studio,android)