안드로이드의 코루틴으로 웹에 있는, URL 이미지를 다운로드하여 화면에 보여주는 방법을 소개합니다.
1. Coroutine 의존성 설정
Gradle 프로젝트에서 코루틴을 사용하려면 아래와 같이 build.gradle
에 의존성을 추가해야 합니다.
dependencies {
...
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
}
2. View(activity_main.xml) 구현
Activity에는 아래와 같이 이미지를 보여줄 ImageView와 ProgressBar를 추가하였습니다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/imageView"
android:layout_width="500dp"
android:layout_height="500dp"
android:scaleType="fitCenter"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone"
app:srcCompat="@mipmap/ic_launcher" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
3. 코루틴으로 URL 이미지 다운로드 및 View에 보여주기
코루틴에서 URL 이미지를 다운로드하고, 다운로드가 완료되면 이미지를 View에 보여주도록 구현해야 합니다.
아래 예제에서는 URL 이미지를 다운로드할 때는 Dispatchers.IO
를 사용하며 async로 가져옵니다.
async는 Deffered를 리턴하며 Deferred.await()
처럼 await()
을 호출하면 비동기적인 작업이 완료될 때까지 대기하게 됩니다. 작업이 완료되면 결과가 리턴됩니다.
getOriginalBitmap()
에서 Bitmap이 리턴되면 Main thread(Dispatchers.Main)에서 loadImage()
를 호출하여 이미지를 View에 보여줍니다.
package com.example.coroutineexample
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import android.widget.ProgressBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import java.net.URL
class MainActivity : AppCompatActivity() {
private val IMAGE_URL = "https://raw.githubusercontent.com/DevTides/JetpackDogsApp/master/app/src/main/res/drawable/dog.png"
private val coroutineScope = CoroutineScope(Dispatchers.Main)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
coroutineScope.launch {
val originalDeferred = coroutineScope.async(Dispatchers.IO) {
getOriginalBitmap()
}
val originalBitmap = originalDeferred.await()
loadImage(originalBitmap)
}
}
private fun getOriginalBitmap(): Bitmap =
URL(IMAGE_URL).openStream().use {
BitmapFactory.decodeStream(it)
}
private fun loadImage(bmp: Bitmap) {
val progressBar = findViewById<ProgressBar>(R.id.progressBar)
val imageView = findViewById<ImageView>(R.id.imageView)
progressBar.visibility = View.GONE
imageView.setImageBitmap(bmp)
imageView.visibility = View.VISIBLE
}
}
4. 이미지 처리
위의 예제는 async()
로 이미지 다운로드를 하고 화면에 보여줍니다. 만약 이미지를 다운로드한 뒤에 약간의 가공을 하고 그 이미지를 화면에 보여주려면 async()
를 추가하여 이미지 처리를 하도록 구현할 수 있습니다.
아래 예제는 Dispatchers.IO
에서 async로 이미지를 다운로드 받고, Dispatchers.Default
에서 async로 이미지 처리를 수행합니다. 결과가 리턴되면 Dispatchers.Main
에서 Image를 View에 보여주도록 합니다.
package com.example.coroutineexample
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import android.widget.ProgressBar
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import java.net.URL
class MainActivity2 : AppCompatActivity() {
private val IMAGE_URL = "https://raw.githubusercontent.com/DevTides/JetpackDogsApp/master/app/src/main/res/drawable/dog.png"
private val coroutineScope = CoroutineScope(Dispatchers.Main)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
coroutineScope.launch {
val originalDeferred = coroutineScope.async(Dispatchers.IO) {
getOriginalBitmap()
}
val originalBitmap = originalDeferred.await()
val filteredDeferred = coroutineScope.async(Dispatchers.Default) {
applyFilter(originalBitmap)
}
val filterBitmap = filteredDeferred.await()
loadImage(filterBitmap)
}
}
private fun getOriginalBitmap(): Bitmap =
URL(IMAGE_URL).openStream().use {
BitmapFactory.decodeStream(it)
}
private fun applyFilter(bmp: Bitmap): Bitmap =
Filter.apply(bmp)
private fun loadImage(bmp: Bitmap) {
val progressBar = findViewById<ProgressBar>(R.id.progressBar)
val imageView = findViewById<ImageView>(R.id.imageView)
progressBar.visibility = View.GONE
imageView.setImageBitmap(bmp)
imageView.visibility = View.VISIBLE
}
}
이 글에서 사용한 예제 코드는 GitHub - CoroutineImageProcessing를 참고해주세요.
References
Related Posts
- Android 14 - 사진/동영상 파일, 일부 접근 권한 소개
- Android - adb push, pull로 파일 복사, 다운로드
- Android 14 - 암시적 인텐트 변경사항 및 문제 해결
- Jetpack Compose - Row와 Column
- Android 13, AOSP 오픈소스 다운로드 및 빌드
- Android 13 - 세분화된 미디어 파일 권한
- Android 13에서 Notification 권한 요청, 알림 띄우기
- Android 13에서 'Access blocked: ComponentInfo' 에러 해결
- 에러 해결: android gradle plugin requires java 11 to run. you are currently using java 1.8.
- 안드로이드 - 코루틴과 Retrofit으로 비동기 통신 예제
- 안드로이드 - 코루틴으로 URL 이미지 불러오기
- Android - 진동, Vibrator, VibrationEffect 예제
- Some problems were found with the configuration of task 에러 수정
- Query method parameters should either be a type that can be converted into a database column or a List
- 우분투에서 Android 12 오픈소스 다운로드 및 빌드
- Android - ViewModel을 생성하는 방법
- Android - Transformations.map(), switchMap() 차이점
- Android - Transformations.distinctUntilChanged() 소개
- Android - TabLayout 구현 방법 (+ ViewPager2)
- Android - 휴대폰 전화번호 가져오는 방법
- Android 12 - Splash Screens 알아보기
- Android 12 - Incremental Install (Play as you Download) 소개
- Android - adb 명령어로 bugreport 로그 파일 추출
- Android - adb 명령어로 App 데이터 삭제
- Android - adb 명령어로 앱 비활성화, 활성화
- Android - adb 명령어로 특정 패키지의 PID 찾기
- Android - adb 명령어로 퍼미션 Grant 또는 Revoke
- Android - adb 명령어로 apk 설치, 삭제
- Android - adb 명령어로 특정 패키지의 프로세스 종료
- Android - adb 명령어로 screen capture 저장
- Android - adb 명령어로 System 앱 삭제, 설치
- Android - adb 명령어로 settings value 확인, 변경
- Android 12 - IntentFilter의 exported 명시적 선언
- Android - adb 명령어로 공장초기화(Factory reset)
- Android - adb logcat 명령어로 로그 출력