我在return place
处不断收到NullPointerException。
在调试应用程序时,代码将跳过onFailure()
和onResponse()
方法。
以前,这可行,但是我将其重构为当前类。
class Repository private constructor() {
private val baseUrl: String = "http://api.openweathermap.org/"
val client = OkHttpClient.Builder()
.addInterceptor(HttpLoggingInterceptor()
.setLevel(HttpLoggingInterceptor.Level.BODY))
.build()
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(MoshiConverterFactory.create())
.client(client)
.build()
val networkApi = retrofit.create(NetworkApi::class.java)
private object Holder { val INSTANCE = Repository() }
companion object {
val instance: Repository by lazy { Holder.INSTANCE }
}
fun fetchWeatherData(placeName: String): Place {
var place: Place? = null
val call: Call<Place> = networkApi.getPlaceWeather(placeName)
call.enqueue(object : Callback<Place> {
override fun onFailure(call: Call<Place>?, t: Throwable?) {
println(t?.message)
}
override fun onResponse(call: Call<Place>?, response: Response<Place>?) {
if (response != null && response.isSuccessful && response.body() != null) {
place = response.body() as Place
println(place.toString())
}
}
})
return place!!
}
}
class MainPresenter(private val view: MainContract.View, val context: Context) : MainContract.Presenter {
val repository = Repository.instance
...
override fun updateListOfPlaces() {
var places = mutableListOf<Place>()
for (index in 0 until favPlaceStrings.size) {
places.add(repository.fetchWeatherData(favPlaceStrings.elementAt(index)))
}
view.showFavouritePlaces(places)
}
}
答案 0 :(得分:1)
您使用改造的方式使其具有异步行为,这意味着onFailure
和onResponse
中的代码可能在您有机会从fetchWeatherData
返回之前或之后运行。换句话说,您无法假设place
将从fetchWeatherData
返回时具有值,而这实际上是正在发生的情况,place
仍然是null
并调用{{1 }}会导致您遇到的空指针异常。
要解决此问题,您可以将改造使用的方式更改为同步,或者使用类似回调的方法。
我个人更喜欢回调方法/响应流,您可以检查here。
使代码同步很可能会导致其他问题,例如不允许在主线程上进行网络调用,并导致应用程序崩溃。
答案 1 :(得分:0)
您需要颠倒逻辑。您不能简单地从正在等待的网络呼叫中“返回数据”
相反,循环遍历列表,进行请求,然后显示/更新视图
for (index in 0 until favPlaceStrings.size) {
val call: Call<Place> = networkApi.getPlaceWeather(favPlaceStrings.elementAt(index))
call.enqueue(object : Callback<Place> {
override fun onFailure(call: Call<Place>?, t: Throwable?) {
println(t?.message)
}
override fun onResponse(call: Call<Place>?, response: Response<Place>?) {
if (response != null && response.isSuccessful && response.body() != null) {
val place: Place = response.body() as Place
places.add(place) // move this list to a field
println(place.toString())
view.showFavouritePlaces(places) // this is fine that it's inside a loop
}
}
})
}