簡體   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