繁体   English   中英

在 Kotlin 中使用协程 IO 线程时使用的主线程

[英]Main Thread used when using coroutine IO Thread in Kotlin

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

奇怪的是,它在使用 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
        }
    }

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

问题是 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))
            }
        }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM