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()
}
반응형
'[Android APP] feat. Kotlin > Kotlin 공부' 카테고리의 다른 글
Kotlin : Fragment의 생명주기 (0) | 2023.02.05 |
---|---|
Kotlin : ImageView 이미지 확대, 축소, 회전 기능 (0) | 2023.02.02 |
Android : Kotlin Retrofit 동기 처리 (0) | 2022.11.02 |
Android Kotlin : 안드로이드 Activity 생명 주기 (0) | 2022.10.22 |
Android Kotlin : GlobalScope와 CoroutineScope (0) | 2022.10.22 |