Kotlin : Thread, Handler

2023. 2. 2. 20:10[Android APP] feat. Kotlin/Kotlin 공부

문제 상황 

Http Connection을 이용해 서버에서 이미지 파일을 input Stream으로 불러와 bitmap으로 변환해준 후 imageView에 띄어주는 작업을 하던 도중 이미지가 띄어지지 않고, Resume() 상태에 있다가 재접속 시에는 띄어지는 현상이 발생했다.

 

 

원인

  • Android에서 HTTP Connection을 사용할 때, Main Thread는 UI를 위한 리소스를 사용해야 하기 때문에 별도의 Thread로 통신해야 한다.
  • 따라서 별도의 Thread를 사용하고, 그 함수 안에서 바로 ImageView에 띄어주도록 작업을 해놨었다.
  •  

Thread란?

  • 동시 작업을 위한 하나의 실행 단위로, 앱을 실행하면 메인 스레드가 실행되고 사용자가 추가로 작업이 필요할 경우 별도의 스레드를 할당해서 동작을 진행할 수 있다.
  • 여기서 이미지 등의 파일과 UI 리소스에 접근이 필요한 경우에 메인 스레드가 아닌 스레드가 리소스를 직접 접근했기 떄문에 문제가 발생했다.
@SuppressLint("SimpleDateFormat")
fun loadFile(imagePath : String, userToken: String,  imageView: ImageView) {
    Thread {
        var `is`: InputStream? = null
  
        try {
            //Header
            val url = URL("http://API 주소")
            val conn = url.openConnection() as HttpURLConnection
            conn.requestMethod = "POST"
            conn.setRequestProperty("Content-Type", "application/json;utf-8")
            conn.setRequestProperty("Accept", "application/json")
            conn.setRequestProperty("token", userToken)
            conn.setRequestProperty("sysCd", CodeList.sysCd)
            conn.connectTimeout = 1500
            //Body
            val gson = Gson()
            val inputJsonData = gson.toJson(DocFileDownLoadDTO("", imagePath, "", ""))
            val writer = OutputStreamWriter(conn.outputStream)

            if (inputJsonData != null) {
                writer.write(
                    inputJsonData.toString(),
                    0,
                    inputJsonData.toString().length
                ) // Parameter 전송
                writer.flush()
            }
            println("responseCode ${conn.responseCode}")
            println("responseCode ${conn.responseMessage}")

            // Status 가 200 일 때
            if (conn.responseCode == HttpURLConnection.HTTP_OK) {
            //이미지를 읽고 비트맵으로 변환 후 imageView에 씌우는 부분
                `is` = conn.inputStream
                val bitmap = BitmapFactory.decodeStream(`is`)
                imageView.setImageBitmap(bitmap)
               //imageView.setImageBitmap(Bitmap.createScaledBitmap(bitmap, 500, 500, false))
            }
            conn.disconnect()
        } catch (e: Exception) {
            println("An error occurred while trying to download a file.")
            e.printStackTrace()
            try {
                `is`?.close()
            } catch (e1: IOException) {
                e1.printStackTrace()
            }
        }
    }.start()
}

 

문제 해결

  • Thread 안에서 UI 리소스에 바로 접근이 아닌 Handler를 사용하여 처리해줬다.
  • 위와 같이 메인 Thread가 아닌 Thread는 작업 순서를 handler를 통해 별도로 관리해주면 해결할 수 있다.
@SuppressLint("SimpleDateFormat")
fun loadFile(imagePath : String, userToken: String, consCode: String, imageView: ImageView) {
    Thread {
        var `is`: InputStream? = null
        //추가
        val handler = Handler(Looper.getMainLooper())
        try {
            //Header
            val url = URL("http://211.107.220.103:${CodeList.portNum}/commManage/docFileDownload")
            val conn = url.openConnection() as HttpURLConnection
            conn.requestMethod = "POST"
            conn.setRequestProperty("Content-Type", "application/json;utf-8")
            conn.setRequestProperty("Accept", "application/json")
            conn.setRequestProperty("token", userToken)
            conn.setRequestProperty("sysCd", CodeList.sysCd)
            conn.connectTimeout = 1500
            //Body
            val gson = Gson()
            val inputJsonData = gson.toJson(DocFileDownLoadDTO(consCode, "", imagePath, "", ""))
            val writer = OutputStreamWriter(conn.outputStream)

            if (inputJsonData != null) {
                writer.write(
                    inputJsonData.toString(),
                    0,
                    inputJsonData.toString().length
                ) // Parameter 전송
                writer.flush()
            }
            println("responseCode ${conn.responseCode}")
            println("responseCode ${conn.responseMessage}")

            // Status 가 200 일 때
            if (conn.responseCode == HttpURLConnection.HTTP_OK) {
                `is` = conn.inputStream
                val bitmap = BitmapFactory.decodeStream(`is`)
                //추가
                handler.postDelayed( {
                    imageView.setImageBitmap(bitmap)
                }, 0)
                //imageView.setImageBitmap(Bitmap.createScaledBitmap(bitmap, 500, 500, false))
            }
            conn.disconnect()
        } catch (e: Exception) {
            println("An error occurred while trying to download a file.")
            e.printStackTrace()
            try {
                `is`?.close()
            } catch (e1: IOException) {
                e1.printStackTrace()
            }
        }
    }.start()
}

 

반응형