代码之家  ›  专栏  ›  技术社区  ›  Zolly

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

  •  -1
  • Zolly  · 技术社区  · 8 年前

    我一直在接受空指针异常 return place .
    当我调试应用程序时,代码跳过 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)
        }
    
    }
    
    2 回复  |  直到 8 年前
        1
  •  0
  •   OneCricketeer Gabriele Mariotti    8 年前

    你需要改变你的逻辑。您不能简单地从等待的网络呼叫“返回数据”

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

    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
                }
            }
        })
    
    }
    
        2
  •  1
  •   Fred    8 年前

    您使用改型的方式使其具有异步行为,这意味着 onFailure onResponse 可能在你有机会返回之前或之后 fetchWeatherData . 换句话说,你不能假设 place 从返回时将具有值 获取天气数据 这就是事实, 地方 仍然是 null 和呼叫 !! 将导致空指针异常。

    要解决这个问题,您要么改变您使用翻新的方式来实现同步,要么使用回调之类的方法。

    就我个人而言,我更喜欢回调方法/反应流,您可以检查一下 here .

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