首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么我在获取JSON时会得到一个NullPointerException?

为什么我在获取JSON时会得到一个NullPointerException?
EN

Stack Overflow用户
提问于 2018-07-09 17:39:58
回答 2查看 391关注 0票数 -1

我一直在return place上拿到一个NullPointerException。

当我调试应用程序时,代码跳过了onFailure()onResponse()方法。

以前,这是有效的,但我将其重构为当前的类。

代码语言:javascript
复制
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)
    }

}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-07-09 20:35:07

你需要反转你的逻辑。您不能简单地从您等待的网络调用中“返回数据”

相反,循环遍历列表,发出请求,然后显示/更新视图

代码语言:javascript
复制
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
            }
        }
    })

}
票数 0
EN

Stack Overflow用户

发布于 2018-07-09 20:25:53

使用retrofit的方式使其具有异步行为,这意味着onFailureonResponse中的代码可能会在您有机会从fetchWeatherData返回之前或之后运行。换句话说,你不能假设当你从fetchWeatherData返回时place会有一个值,这就是实际发生的情况,place仍然是null,调用!!会导致空指针异常。

要解决此问题,您可以更改使用改进的方式以实现同步,或者使用像回调这样的方法。

就我个人而言,我更喜欢回调方法/反应流,这是你可以查看here的。

使代码同步很可能会导致其他问题,如主线程上的网络调用,这是不允许的,并使应用程序崩溃。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51242443

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档