Основная нить, используемая при использовании сопрограммы IO Thread в Kotlin - PullRequest
0 голосов
/ 31 января 2020

Я пытаюсь получить данные с сервера, используя Volley и HTTPURLConnection. Используется сопрограмма IO Thread для предотвращения блокировки основного потока, но экран останавливается при выполнении задания (что означает, что основной поток заблокирован).

Странно то, что он отлично работает при выполнении других заданий с использованием Jsoup и HTTPURLConnection. Единственные различия, которые я могу найти, это то, что он не использует лямбду.

В чем может быть проблема? Заранее спасибо.

* Edit1: я использовал suspend и withContext, но обнаружил, что их удаление не решает проблему.

Code of 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
        }
    }

1 Ответ

0 голосов
/ 31 января 2020

Нашел решение. Ключом была разница между двумя случаями.

Проблема была в лямбде. Когда используется лямбда, создается новый блок, и этот блок отделен от внешнего блока. Это означает, что лямбда-блок снова запускается в главном потоке.

Таким образом, повторное выполнение сопрограммы внутри лямбда-блока решает проблему. Надеюсь, это поможет другим новичкам.

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))
            }
        }
    }
...