首页 > 解决方案 > 有没有办法同步运行 Okhttps 请求?

问题描述

所以我正在尝试一个应用程序,我正在发出一个 okhttp 请求。我发现这个请求任务是在它自己的线程上进行的,这会导致异步行为。

在下方,您会看到我的函数,它从 API 获取数据,以及 onCreateView 函数,我在其中调用 fetchData()。

@Throws(IOException::class)
    fun fetchData() {
        val client = OkHttpClient()
        val request: Request = Request.Builder()
            .url("https://www.themealdb.com/api/json/v1/1/search.php?f=a")
            .build()

        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                call.cancel()
            }

            @Throws(IOException::class)
            override fun onResponse(call: Call, response: Response) {
                val responseString = U.formatJson(response.body?.string())
                val meals = Gson().fromJson(responseString, Meals::class.java)
                
                Log.d(TAG, "First")
                
            }
        })
    }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        fetchData()

        Log.d(TAG, "second")

        return inflater.inflate(R.layout.fragment_home, container, false)
    }

所以我把这些日志放在这里看看,哪个 Log 被首先调用,并且由于 fetchData() 是异步的,很明显 onCreateView() 中的 Log.d(TAG, "second") 被首先调用。因此,如果我尝试使用下面请求的数据,我会得到 null,因为请求尚未完成。这就是我的问题。调用函数后我需要使用请求的数据。

有什么解决方案可以让我以某种方式同步进行 fetchData() 但不阻塞主线程?

标签: androidkotlinokhttp

解决方案


您不能在主线程上运行网络请求。它必须是异步的。只是猜测你在做什么,我会在你的 fetch 函数中添加一个回调并像这样使用它。

fun fetchData(callback: (Meals?) -> Unit) {
    val client = OkHttpClient()
    val request: Request = Request.Builder()
        .url("https://www.themealdb.com/api/json/v1/1/search.php?f=a")
        .build()

    client.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            call.cancel()
            callback(null)
        }

        @Throws(IOException::class)
        override fun onResponse(call: Call, response: Response) {
            val responseString = U.formatJson(response.body?.string())
            val meals = Gson().fromJson(responseString, Meals::class.java)
            callback(meals)
        }
    })
}

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    fetchData { meals ->
        if (meals == null) 
            showErrorMessage()
        else
            updateSomeListAdapterWithMeals(meals)
    }

    return inflater.inflate(R.layout.fragment_home, container, false)
}

fetchData由于回调将在稍后触发,因此在膨胀视图之前调用并不重要。


推荐阅读