Reputation: 35
I'm trying to get data from server using Volley and HTTPURLConnection. Used coroutine IO Thread to prevent blocking Main thread, but screen stops when doing the job(which means main thread is blocked).
Weird thing is, it works perfectly when doing other jobs using Jsoup and HTTPURLConnection. Only differences I can find is it doesn't use lambda.
What could be the problem? Thanks in advance.
*Edit1: I used suspend and withContext, but I found that removing those don't solve the problem.
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()
}
}
Code of object 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
}
}
Upvotes: 0
Views: 1060
Reputation: 35
Found the solution. The key was the difference between two cases.
The problem was lambda. When lambda is used, new block is created, and that block is separate from outer block. That means lambda block runs again in Main thread.
So making coroutine again inside lambda block solves the problem. Hope this helps to other newbies.
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))
}
}
}
Upvotes: 1