MVVM架构天气应用UI未更新:ViewModel获取位置后界面无变化
MVVM天气应用:迁移定位逻辑到ViewModel后UI不更新的解决方案
问题概述
开发采用MVVM架构的天气应用时,将位置获取逻辑从MainActivity迁移到WeatherViewModel后,界面无法更新天气数据。此前直接在Activity中实现定位逻辑时,UI能正常展示结果。
代码问题分析
1. ViewModel中fetchLocation()返回值逻辑错误
ViewModel的fetchLocation()方法无论权限是否已授予,最终都返回true,导致MainActivity中执行权限申请后直接return,跳过了weatherResp的观察者注册,后续数据更新无法通知UI。
2. MainActivity缺失权限申请回调
申请定位权限后,未处理权限授予结果,导致用户同意权限后,不会重新触发定位获取流程,无法获取位置并请求天气数据。
3. 冗余的FusedLocationProviderClient实例
MainActivity中自行初始化了fusedLocationProviderClient,但ViewModel已通过Hilt注入该实例,Activity中的此实例属于冗余代码,可移除。
修复后的代码
WeatherViewModel.kt 修复
@HiltViewModel class WeatherViewModel @Inject constructor( private val repo: WeatherRepository, private val application: Application, private val fusedLocationProviderClient: FusedLocationProviderClient ) : ViewModel() { private val _resp = MutableLiveData<WeatherDTO>() val weatherResp: LiveData<WeatherDTO> get() = _resp private val _cord = MutableLiveData<Coord>() val cord: LiveData<Coord> get() = _cord fun getWeather(latitude: Double, longitude: Double) = viewModelScope.launch { repo.getWeather(latitude, longitude).let { response -> if (response.isSuccessful) { _resp.postValue(response.body()) } else { Log.d("Weather Error", "getWeather Error Response: ${response.message()}") } } } // 修正返回值逻辑:仅当权限未授予时返回true fun fetchLocation(): Boolean { val task = fusedLocationProviderClient.lastLocation if (ActivityCompat.checkSelfPermission( application, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission( application, android.Manifest.permission.ACCESS_COARSE_LOCATION ) != PackageManager.PERMISSION_GRANTED ) { return true } task.addOnSuccessListener { it?.let { location -> getWeather(location.latitude, location.longitude) } } // 权限已授予时返回false return false } private fun getAddressName(lat: Double, long: Double): String { Log.d("lat", lat.toString()) var addressName = " " val geoCoder = Geocoder(application, Locale.getDefault()) val address = geoCoder.getFromLocation(lat, long, 1) if (address != null) { addressName = address[0].subAdminArea } Log.d("Address", address.toString()) Log.d("subadmin", addressName.toString()) return addressName } }
MainActivity.kt 修复
@AndroidEntryPoint class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding private lateinit var weatherModel: WeatherViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) weatherModel = ViewModelProvider(this)[WeatherViewModel::class.java] // 先注册观察者,确保数据更新能被UI接收 weatherModel.weatherResp.observe(this) { weather -> binding.apply { tvDescription.text = weather.weather[0].description livelocation.setOnClickListener { Toast.makeText(this@MainActivity, "this is rohit", Toast.LENGTH_SHORT).show() } tvWind.text = "${weather.wind.speed} Km/h" humidity.text = weather.main.humidity.toString() val tempInC = weather.main.temp - 273.15 val number3digits = (tempInC * 1000.0).roundToInt() / 1000.0 tvTemperature.text = number3digits.toString() visibility.text = weather.visibility.toString() } } // 处理定位逻辑 if (weatherModel.fetchLocation()) { ActivityCompat.requestPermissions( this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), 101 ) } } // 添加权限申请结果回调 override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == 101) { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限授予后,重新触发定位获取 weatherModel.fetchLocation() } else { Toast.makeText(this, "定位权限未授予,无法获取天气数据", Toast.LENGTH_SHORT).show() } } } }
关键修复说明
- 调整
fetchLocation()返回值:仅当权限未授予时返回true,确保权限已授予时MainActivity能正常注册观察者。 - 添加权限回调:在
onRequestPermissionsResult中处理权限授予结果,重新触发定位流程。 - 调整观察者注册顺序:先注册
weatherResp的观察者,再执行定位逻辑,避免数据更新时UI未监听。 - 移除冗余代码:删除MainActivity中自行初始化的
fusedLocationProviderClient,统一使用ViewModel中注入的实例。
内容的提问来源于stack exchange,提问作者Jadu
相关产品推荐
相关产品推荐

