【问题标题】:Main Thread used when using coroutine IO Thread in Kotlin在 Kotlin 中使用协程 IO 线程时使用的主线程
【发布时间】:2020-01-31 04:46:06
【问题描述】:

我正在尝试使用 Volley 和 HTTPURLConnection 从服务器获取数据。使用协程 IO 线程来防止阻塞主线程,但在执行工作时屏幕停止(这意味着主线程被阻塞)。

奇怪的是,它在使用 Jsoup 和 HTTPURLConnection 做其他工作时效果很好。我能找到的唯一区别是它不使用 lambda。

可能是什么问题?提前致谢。

*Edit1:我使用了suspend和withContext,但我发现删除它们并不能解决问题。

ConDetailActivity.kt 代码

    val scope = CoroutineScope(Dispatchers.IO)
    private fun initialize(context: Context,idx:String) = scope.launch{
        try{
            ConCrawler.getConData(context,idx) {data ->
                CoroutineScope(Dispatchers.Main).launch { adapter.addData(data.imgDataList) }
                progressbar.visibility = View.INVISIBLE
            }

        }catch(e:Exception){
            e.printStackTrace()
        }
    }

对象 ConCrawler 的代码

    suspend fun getConData(context: Context, idx: String, returnConData: (condata: ConDataforReturn) -> Unit) = withContext(Dispatchers.Default) {
        val params = HashMap<String, String>()
        val cd = arrayListOf<ConImgData?>()
        var title = ""
        params.put("package_idx", idx)
        VolleyRequest(context, params, "https://dccon.dcinside.com/index/package_detail") { response ->
            val answer = JSONObject(response)
            var json = answer.getJSONArray("detail")
            title = answer.getJSONObject("info").getString("title")
            for (i in 0..(json.length() - 1)) {
                val v = json.getJSONObject(i)
                cd.add(ConImgData(v.getString("title"), v.getString("ext"), runBlocking { getBitmapFromURL("https://dcimg5.dcinside.com/dccon.php?no=" + v.getString("path")) }, v.getString("path")))
            }
            returnConData(ConDataforReturn(title, cd))
        }
    }

    fun VolleyRequest(context: Context, params: HashMap<String, String>, link: String, success: (response: String) -> Unit) {
        val queue = Volley.newRequestQueue(context)
        val stringRequest = object : StringRequest(Method.POST, link,
            Response.Listener<String> { response ->
                Log.e("response", response.toString())
                success(response)
            },
            Response.ErrorListener { error ->
                error.printStackTrace()
            }) {
            override fun getHeaders(): MutableMap<String, String> {
                val headers = mutableMapOf<String, String>()
                /*unused headers
                headers.put("user-agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36")
                headers.put("origin","https://dccon.dcinside.com")
                headers.put("referer","https://dccon.dcinside.com")
                headers.put("content-type","multipart/form-data")
                 */
                headers.put("x-requested-with", "XMLHttpRequest")
                return headers
            }

            override fun getParams(): MutableMap<String, String> {
                return params
            }

        }
        stringRequest.setShouldCache(false)
        queue.add(stringRequest)
    }
    suspend fun getBitmapFromURL(src: String): Bitmap? = withContext(Dispatchers.Default) {
        try {
            val url = URL(src)
            val connection: HttpURLConnection = url.openConnection() as HttpURLConnection
            connection.setRequestProperty("Referer", "https://dccon.dcinside.com")
            connection.setRequestProperty("Sec-Fetch-Mode", "no-cors")
            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36")
            connection.setDoInput(true)
            connection.connect()
            val input: InputStream = connection.getInputStream()
            BitmapFactory.decodeStream(input)
        } catch (e: Exception) { // Log exception
            e.printStackTrace()
            null
        }
    }

【问题讨论】:

    标签: android multithreading kotlin kotlin-coroutines


    【解决方案1】:

    找到了解决方案。关键是两种情况的区别。

    问题是 lambda。使用 lambda 时,会创建新块,并且该块与外部块分开。 这意味着 lambda 块在主线程中再次运行。

    所以在 lambda 块内再次创建协程可以解决问题。希望这对其他新手有所帮助。

    fun getConData(context: Context, idx: String, returnConData: (condata: ConDataforReturn) -> Unit) {
            val params = HashMap<String, String>()
            val cd = arrayListOf<ConImgData?>()
            var title = ""
            params.put("package_idx", idx)
            VolleyRequest(context, params, "https://dccon.dcinside.com/index/package_detail") { response ->
                CoroutineScope(Dispatchers.IO).launch {
                    val answer = JSONObject(response)
                    var json = answer.getJSONArray("detail")
                    title = answer.getJSONObject("info").getString("title")
                    for (i in 0..(json.length() - 1)) {
                        val v = json.getJSONObject(i)
                        var a = getBitmapFromURL("https://dcimg5.dcinside.com/dccon.php?no=" + v.getString("path"))
                        cd.add(ConImgData(v.getString("title"), v.getString("ext"), a, v.getString("path")))
                    }
                    returnConData(ConDataforReturn(title, cd))
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-08
      • 2020-05-21
      • 1970-01-01
      • 2014-12-16
      • 2022-01-13
      • 1970-01-01
      • 1970-01-01
      • 2020-10-15
      相关资源
      最近更新 更多