本人kotlin初学者,在跟着这本书学习时发现,这个天气预报很多代码已经不适用现在的版本了,现在遇到了很多问题,请问有没有人更新了代码,或者能指导我修改出现的问题
添加了问题代码,不知道怎么放完整的文件
com.sunnyweather.android.logic.Repository
package com.sunnyweather.android.logic
//import androidx.lifecycle.liveData
import com.sunnyweather.android.logic.dao.PlaceDao
import com.sunnyweather.android.logic.model.Place
import com.sunnyweather.android.logic.model.Weather
import com.sunnyweather.android.logic.network.SunnyWeatherNetwork
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
//import kotlinx.coroutines.flow.internal.NopCollector.emit
import kotlin.Result.Companion.failure
import kotlin.coroutines.CoroutineContext
object Repository {
fun searchPlaces(query: String) {
val fire = fire(Dispatchers.IO) {
val placeResponse = SunnyWeatherNetwork.searchPlaces(query)
if (placeResponse.status == "ok") {
val places = placeResponse.places
Result.success(places)
} else {
failure(RuntimeException("response status is ${placeResponse.status}"))
}
}
return fire
}
fun refreshWeather(lng: String, lat: String, placeName: String) = fire(Dispatchers.IO) {
coroutineScope {
val deferredRealtime = async {
SunnyWeatherNetwork.getRealtimeWeather(lng, lat)
}
val deferredDaily = async {
SunnyWeatherNetwork.getDailyWeather(lng, lat)
}
val realtimeResponse = deferredRealtime.await()
val dailyResponse = deferredDaily.await()
if (realtimeResponse.status == "ok" && dailyResponse.status == "ok") {
val weather = Weather(realtimeResponse.result.realtime, dailyResponse.result.daily)
Result.success(weather)
} else {
failure(
RuntimeException(
"realtime response status is ${realtimeResponse.status}" +
"daily response status is ${dailyResponse.status}"
)
)
}
}
}
fun savePlace(place: Place) = PlaceDao.savePlace(place)
fun getSavedPlace() = PlaceDao.getSavedPlace()
fun isPlaceSaved() = PlaceDao.isPlaceSaved()
private fun <T> fire(context: CoroutineContext, block: suspend () -> Result<T>) =
liveData<Result<T>>(context) {
val result = try {
block()
} catch (e: Exception) {
failure<T>(e)
}
emit(result)
}
}
错误描述
com.sunnyweather.android.ui.place.PlaceAdapter
package com.sunnyweather.android.ui.place
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.sunnyweather.android.R
import com.sunnyweather.android.logic.model.Place
import com.sunnyweather.android.ui.weather.WeatherActivity
//import kotlinx.android.synthetic.main.activity_weather.*
class PlaceAdapter(private val fragment: PlaceFragment, private val placeList: List<Place>) : RecyclerView.Adapter<PlaceAdapter.ViewHolder>() {
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val placeName: TextView = view.findViewById(R.id.placeName)
val placeAddress: TextView = view.findViewById(R.id.placeAddress)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.place_item, parent, false)
val holder = ViewHolder(view)
holder.itemView.setOnClickListener {
val position = holder.adapterPosition
val place = placeList[position]
val activity = fragment.activity
if (activity is WeatherActivity) {
activity.drawerLayout.closeDrawers()
activity.viewModel.locationLng = place.location.lng
activity.viewModel.locationLat = place.location.lat
activity.viewModel.placeName = place.name
activity.refreshWeather()
} else {
val intent = Intent(parent.context, WeatherActivity::class.java).apply {
putExtra("location_lng", place.location.lng)
putExtra("location_lat", place.location.lat)
putExtra("place_name", place.name)
}
fragment.startActivity(intent)
activity?.finish()
}
fragment.viewModel.savePlace(place)
}
return holder
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val place = placeList[position]
holder.placeName.text = place.name
holder.placeAddress.text = place.address
}
override fun getItemCount() = placeList.size
}
错误描述
package com.sunnyweather.android.ui.place
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager
import com.sunnyweather.android.MainActivity
import com.sunnyweather.android.R
import com.sunnyweather.android.ui.weather.WeatherActivity
//import kotlinx.android.synthetic.main.fragment_place.*
class PlaceFragment : Fragment() {
val viewModel by lazy { ViewModelProviders.of(this).get(PlaceViewModel::class.java) }
private lateinit var adapter: PlaceAdapter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_place, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (activity is MainActivity && viewModel.isPlaceSaved()) {
val place = viewModel.getSavedPlace()
val intent = Intent(context, WeatherActivity::class.java).apply {
putExtra("location_lng", place.location.lng)
putExtra("location_lat", place.location.lat)
putExtra("place_name", place.name)
}
startActivity(intent)
activity?.finish()
return
}
val layoutManager = LinearLayoutManager(activity)
private val recyclerView:
recyclerView.layoutManager = layoutManager
adapter = PlaceAdapter(this, viewModel.placeList)
recyclerView.adapter = adapter
searchPlaceEdit.addTextChangedListener { editable ->
val content = editable.toString()
if (content.isNotEmpty()) {
viewModel.searchPlaces(content)
} else {
recyclerView.visibility = View.GONE
bgImageView.visibility = View.VISIBLE
viewModel.placeList.clear()
adapter.notifyDataSetChanged()
}
}
viewModel.placeLiveData.observe(this, Observer{ result ->
val places = result.getOrNull()
if (places != null) {
recyclerView.visibility = View.VISIBLE
bgImageView.visibility = View.GONE
viewModel.placeList.clear()
viewModel.placeList.addAll(places)
adapter.notifyDataSetChanged()
} else {
Toast.makeText(activity, "未能查询到任何地点", Toast.LENGTH_SHORT).show()
result.exceptionOrNull()?.printStackTrace()
}
})
}
}
问题
app/src/main/java/com/sunnyweather/android/ui/place/PlaceViewModel.kt
package com.sunnyweather.android.ui.place
import androidx.lifecycle.*
import com.sunnyweather.android.logic.Repository
import com.sunnyweather.android.logic.model.Place
class PlaceViewModel : ViewModel() {
private val searchLiveData = MutableLiveData<String>()
val placeList = ArrayList<Place>()
val placeLiveData = Transformations.switchMap(searchLiveData) { query ->
Repository.searchPlaces(query)
}
fun searchPlaces(query: String) {
searchLiveData.value = query
}
fun savePlace(place: Place) = Repository.savePlace(place)
fun getSavedPlace() = Repository.getSavedPlace()
fun isPlaceSaved() = Repository.isPlaceSaved()
}
package com.sunnyweather.android.ui.weather
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import com.sunnyweather.android.R
import com.sunnyweather.android.logic.model.Weather
import com.sunnyweather.android.logic.model.getSky
//import kotlinx.android.synthetic.main.activity_weather.*
//import kotlinx.android.synthetic.main.forecast.*
//import kotlinx.android.synthetic.main.life_index.*
//import kotlinx.android.synthetic.main.now.*
import java.text.SimpleDateFormat
import java.util.*
class WeatherActivity : AppCompatActivity() {
val viewModel by lazy { ViewModelProviders.of(this).get(WeatherViewModel::class.java) }
@SuppressLint("PrivateResource")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (Build.VERSION.SDK_INT >= 21) {
val decorView = window.decorView
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
window.statusBarColor = Color.TRANSPARENT
}
setContentView(R.layout.activity_weather)
if (viewModel.locationLng.isEmpty()) {
viewModel.locationLng = intent.getStringExtra("location_lng") ?: ""
}
if (viewModel.locationLat.isEmpty()) {
viewModel.locationLat = intent.getStringExtra("location_lat") ?: ""
}
if (viewModel.placeName.isEmpty()) {
viewModel.placeName = intent.getStringExtra("place_name") ?: ""
}
viewModel.weatherLiveData.observe(this, Observer { result ->
val weather = result.getOrNull()
if (weather != null) {
showWeatherInfo(weather)
} else {
Toast.makeText(this, "无法成功获取天气信息", Toast.LENGTH_SHORT).show()
result.exceptionOrNull()?.printStackTrace()
}
swipeRefresh.isRefreshing = false
})
swipeRefresh.setColorSchemeResources(com.google.android.material.R.color.design_dark_default_color_primary)
refreshWeather()
swipeRefresh.setOnRefreshListener {
refreshWeather()
}
navBtn.setOnClickListener {
drawerLayout.openDrawer(GravityCompat.START)
}
drawerLayout.addDrawerListener(object : DrawerLayout.DrawerListener {
override fun onDrawerStateChanged(newState: Int) {}
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {}
override fun onDrawerOpened(drawerView: View) {}
override fun onDrawerClosed(drawerView: View) {
val manager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
manager.hideSoftInputFromWindow(drawerView.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
}
})
}
fun refreshWeather() {
viewModel.refreshWeather(viewModel.locationLng, viewModel.locationLat)
swipeRefresh.isRefreshing = true
}
private fun showWeatherInfo(weather: Weather) {
placeName.text = viewModel.placeName
val realtime = weather.realtime
val daily = weather.daily
// 填充now.xml布局中数据
val currentTempText = "${realtime.temperature.toInt()} ℃"
currentTemp.text = currentTempText
currentSky.text = getSky(realtime.skycon).info
val currentPM25Text = "空气指数 ${realtime.airQuality.aqi.chn.toInt()}"
currentAQI.text = currentPM25Text
nowLayout.setBackgroundResource(getSky(realtime.skycon).bg)
// 填充forecast.xml布局中的数据
forecastLayout.removeAllViews()
val days = daily.skycon.size
for (i in 0 until days) {
val skycon = daily.skycon[i]
val temperature = daily.temperature[i]
val view = LayoutInflater.from(this).inflate(R.layout.forecast_item, forecastLayout, false)
val dateInfo = view.findViewById(R.id.dateInfo) as TextView
val skyIcon = view.findViewById(R.id.skyIcon) as ImageView
val skyInfo = view.findViewById(R.id.skyInfo) as TextView
val temperatureInfo = view.findViewById(R.id.temperatureInfo) as TextView
val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
dateInfo.text = simpleDateFormat.format(skycon.date)
val sky = getSky(skycon.value)
skyIcon.setImageResource(sky.icon)
skyInfo.text = sky.info
val tempText = "${temperature.min.toInt()} ~ ${temperature.max.toInt()} ℃"
temperatureInfo.text = tempText
forecastLayout.addView(view)
}
// 填充life_index.xml布局中的数据
val lifeIndex = daily.lifeIndex
coldRiskText.text = lifeIndex.coldRisk[0].desc
dressingText.text = lifeIndex.dressing[0].desc
ultravioletText.text = lifeIndex.ultraviolet[0].desc
carWashingText.text = lifeIndex.carWashing[0].desc
weatherLayout.visibility = View.VISIBLE
}
}
问题
app/src/main/java/com/sunnyweather/android/ui/weather/WeatherViewModel.kt
package com.fuckweather.android.ui.weather
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel
import com.fuckweather.android.logic.Repository
import com.fuckweather.android.logic.model.Location
//import android.location.Location
class WeatherViewModel : ViewModel() {
private val locationLiveData = MutableLiveData<Location>()
var locationLng = ""
var locationLat = ""
var placeName = ""
val weatherLiveData = Transformations.switchMap(locationLiveData) { location ->
// Repository.refreshWeather(location.lng, location.lat)
Repository.refreshWeather(location.lng, location.lat, placeName)
}
fun refreshWeather(lng: String, lat: String) {
locationLiveData.value = Location(lng, lat)
}
}
问题
看不到你的代码。
参考:《第一行代码Android第三版》天气预报项目书中代码错误,链接:https://blog.csdn.net/Grant1982/article/details/113736160
可以把你的问题发出来,郭神写这本书是2019年,过了三年多了,难免会有问题,变化最快的应该是gradle,下载书的源码试试
代码传到 gitee 上或者百度网盘,我有时间的话,给你下载下来看看