[Android] Network Programming

leeehaยท2022๋…„ 11์›” 27์ผ
0
post-thumbnail

Network Programming

  • ํผ๋ฏธ์…˜ ํ•„์š”
<uses-permission android:name="android.permission.INTERNET"/>

๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ข…๋ฅ˜

HttpURLConnection

  • java SE์—์„œ ์ œ๊ณต๋˜๋Š” API
  • ์•ˆ๋“œ๋กœ์ด๋“œ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ์ดˆ๊ธฐ ๋ฒ„์ „๋ถ€ํ„ฐ ์ œ๊ณต

HttpClient

  • Apache HTTP ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • ์•ˆ๋“œ๋กœ์ด๋“œ ์ดˆ๊ธฐ HttpURLConnection ๋ถ€๋ถ„์— ๋‚ด๋ถ€์ ์ธ ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด์„œ, ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํฌํ•จ๋˜์–ด ๋งŽ์ด ์‚ฌ์šฉํ•˜๋˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • Android ๋ฒ„์ „ 6์—์„œ๋Š” Apache HTTP ํด๋ผ์ด์–ธํŠธ์— ๋Œ€ํ•œ ์ง€์›์ด ์—†์–ด์ง.
  • Android ๋ฒ„์ „ 9๋ถ€ํ„ฐ๋Š” ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ bootclasspath์—์„œ ์ œ๊ฑฐ๋˜๊ณ  ๊ธฐ๋ณธ์ ์œผ๋กœ ์•ฑ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ ๋จ.
  • Android ๋ฒ„์ „ 9 ์ด์ƒ์„ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ์•ฑ์ด Apache HTTP ํด๋ผ์ด์–ธํŠธ๋ฅผ ๊ณ„์† ์‚ฌ์šฉํ•˜๋ ค๋ฉด AndroidManifest.xml ํŒŒ์ผ์— <uses-library> ํƒœ๊ทธ๋กœ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.

Volley

  • 2013๋…„ Google I/O์—์„œ ๋ฐœํ‘œํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • http ํ†ต์‹ ์„ ์œ„ํ•œ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ ์ œ๊ณต
  • 1.0.0 ๋ฒ„์ „์—์„œ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ Apache HTTP ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ–ˆ์œผ๋‚˜, 1.1.1 ๋ฒ„์ „๋ถ€ํ„ฐ๋Š” Apache HTTP ์ข…์†์„ฑ์ด ์ œ๊ฑฐ๋˜์—ˆ๋‹ค.

okHttp

  • square๋ผ๋Š” ํšŒ์‚ฌ์—์„œ ๋งŒ๋“  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

Retrofit

  • 2013๋…„์— 1.0 ๋ฒ„์ „, 2016๋…„์— 2.0 ๋ฒ„์ „์ด ๋ฐœํ‘œ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • ์•ˆ๋“œ๋กœ์ด๋“œ ๋„คํŠธ์›Œํฌ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ๊ฐ€์žฅ ์œ ๋ช…ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • ๋‚ด๋ถ€์ ์œผ๋กœ okHttp๋ฅผ ์ด์šฉํ•œ๋‹ค.

HTTP ๊ด€๋ จ ๋ณด์•ˆ ์ •์ฑ…

  • API Level 28๋ถ€ํ„ฐ ๋„คํŠธ์›Œํฌ ๊ด€๋ จ ๋ณด์•ˆ ์ •์ฑ…์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค.
  • https๋Š” ๋ฌธ์ œ ์—†์ง€๋งŒ, http๋Š” ์ถ”๊ฐ€ ์„ค์ •์ด ํ•„์š”ํ•˜๋‹ค.

๋ฐฉ๋ฒ• 1

  • usesCleartextTraffic ์„ค์ •
  • ์ด์ „์—๋„ ์žˆ์—ˆ๋˜ ์†์„ฑ์ด์ง€๋งŒ API Level 28๋ถ€ํ„ฐ๋Š” ๊ธฐ๋ณธ๊ฐ’์ด false๋กœ ๋ณ€๊ฒฝ๋˜์–ด์„œ, http๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋ช…์‹œ์ ์œผ๋กœ true๋กœ ์„ค์ •ํ•ด์ค˜์•ผ ํ•œ๋‹ค.
<application 
	android:usesCleartextTraffic="true">

๋ฐฉ๋ฒ• 2

  • network_security_config๋ฅผ ๋ฃจํŠธ ํƒœ๊ทธ๋กœ ํ•˜๋Š” xml ํŒŒ์ผ ์ƒ์„ฑ
  • ์ด ํŒŒ์ผ์— ์„ค์ •๋œ ๋„๋ฉ”์ธ, IP ์ฃผ์†Œ์— ํ•ด๋‹นํ•˜๋Š” ์„œ๋ฒ„๋ž‘๋งŒ http ํ†ต์‹  ํ—ˆ์šฉ


๋„คํŠธ์›Œํฌ ์ •๋ณด ํ™•์ธ

ConnectivityManager

  • ConnectivityManager๋ผ๋Š” ์‹œ์Šคํ…œ ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•ด ํ•ธ๋“œํฐ์˜ ๋„คํŠธ์›Œํฌ ์ƒํƒœ๋ฅผ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์•„๋ž˜ ํผ๋ฏธ์…˜์„ ๋ถ€์—ฌํ•ด์ค˜์•ผ ํ•œ๋‹ค.
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  • ConnectivityManager์˜ getActiveNetwork()๋ฅผ ์ด์šฉํ•ด Network ๊ฐ์ฒด ํš๋“
  • Network ๊ฐ์ฒด๋ฅผ getNetworkCapabilities() ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ง€์ •ํ•˜๋ฉด, ํ˜„์žฌ ์ ‘์†๋œ ๋„คํŠธ์›Œํฌ ์ •๋ณด ํš๋“ ๊ฐ€๋Šฅ
val nw = connectivityManager.activeNetwork
val actNw = connectivityManager.getNetworkCapabilities(nw)
  • hasTransport() ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ํ˜„์žฌ ํ•ธ๋“œํฐ์ด ์™€์ดํŒŒ์ด์— ์ ‘์†๋œ ์ƒํƒœ์ธ์ง€, ์ด๋™ ํ†ต์‹ ์‚ฌ๋ง์— ์ ‘์†๋œ ์ƒํƒœ์ธ์ง€ ํŒŒ์•…ํ•œ๋‹ค. ๋‘ ๊ฐœ ๋ชจ๋‘์— ํ•ด๋‹น๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ์˜คํ”„๋ผ์ธ ์ƒํƒœ๋ผ๊ณ  ํŒ๋‹จํ•œ๋‹ค.
actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> {
	return "wifi online"
}
actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> {
	return "cellular available"
}

์‹ค์Šต ์˜ˆ์ œ

package com.tutorial.c85

import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val resultView = findViewById<TextView>(R.id.resultView)
        resultView.text = isNetworkAvailable()
    }

    private fun isNetworkAvailable(): String {
        val manager = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val nw = manager.activeNetwork ?: return "offline"
            val actNw = manager.getNetworkCapabilities(nw) ?: return "offline"
            return when {
                actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> {
                    return "wifi online"
                }
                actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> {
                    return "cellular online"
                }
                else -> return "offline"
            }
        }else{
            return if(manager.activeNetworkInfo?.isConnected!!) {
                "online"
            }else{
                "offline"
            }
        }
    }
}


Retrofit ๊ตฌ์กฐ

  • Retrofit2๋Š” Square์‚ฌ์—์„œ ๋งŒ๋“  HTTP ํ†ต์‹ ์„ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • ๋‚ด๋ถ€์ ์œผ๋กœ okHttp ์‚ฌ์šฉ

๊ฐœ๋ฐœ์ž๊ฐ€ ๋„คํŠธ์›Œํฌ ์‹œ ํ˜ธ์ถœ๋˜์–ด์•ผ ํ•  ํ•จ์ˆ˜๋ฅผ ๊ฐ–๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋ ˆํŠธ๋กœํ•์— ๋“ฑ๋ก์‹œํ‚ค๋ฉด, ๋ ˆํŠธ๋กœํ•์€ ํ•ด๋‹น ํ•จ์ˆ˜์— ๋„คํŠธ์›Œํ‚น๊ณผ ๊ด€๋ จ๋œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ Call ๊ฐ์ฒด๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Call ๊ฐ์ฒด์˜ enqueue ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋„คํŠธ์›Œํ‚น์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ dependency

  • com.squareup.retrofit2:retrofit (๋ ˆํŠธ๋กœํ• ์‚ฌ์šฉ์„ ์œ„ํ•œ ํ•„์ˆ˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)
  • JSON, XML ํŒŒ์‹ฑ์„ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ค‘์— ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • parser๋Š” JSON, XML์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋ธ ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.
  • ๋ชจ๋ธ ํด๋ž˜์Šค๋ž€ ์„œ๋ฒ„์™€ ์ฃผ๊ณ ๋ฐ›๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ํด๋ž˜์Šค์ด๋ฉฐ, VO (Value Object) ๋˜๋Š” DTO (Data Transfer Object) ๋ผ๊ณ ๋„ ๋ถ€๋ฅธ๋‹ค.

cf) DAO, DTO, VO๋ž€?

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

Gson ๋ง๊ณ ๋„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‹ค์–‘ํ•œ parse๋“ค์ด ์žˆ๋‹ค.

์ด๋Ÿฐ parser๋“ค์€ JSON ๋˜๋Š” XML ๋ฐ์ดํ„ฐ๋ฅผ ํŒŒ์‹ฑํ•˜์—ฌ ๋ชจ๋ธ ํด๋ž˜์Šค ๊ฐ์ฒด์— ๋‹ด์•„์ฃผ๋Š” ๊ฒƒ์„ ์ž๋™ํ™” ํ•œ๋‹ค.

// json ๋ฐ์ดํ„ฐ 
{
	"id": 7,
	"email": "michael.lawson@reqres.in",
	"first_name": "Michael",
	"last_name": "Lawson",
	"avatar": "https://reqres.in/img/faces/7-image.jpg"
}
// ๋ชจ๋ธ ํด๋ž˜์Šค 
data class UserModel(
	var id: String, 
    @SerializedName("first_name") 
	var firstName: String,
	@SerializedName("last_name")
	var lastName: String, var avatar: String, var avatarBitmap: Bitmap 
)

Retrofit ํ™œ์šฉ

์„œ๋น„์Šค ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ

  1. ๋„คํŠธ์›Œํฌ ํ†ต์‹ ์— ์ด์šฉ๋  ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ
  2. ์ธํ„ฐํŽ˜์ด์Šค ์•ˆ์— ๋„คํŠธ์›Œํฌ ํ†ต์‹ ์ด ํ•„์š”ํ•œ ์ˆœ๊ฐ„์— ํ˜ธ์ถœํ•  ํ•จ์ˆ˜ ์„ ์–ธ
  3. ํ•จ์ˆ˜๋“ค์€ ์‹ค์ œ ๋„คํŠธ์›Œํ‚น์ด ๊ฐ€๋Šฅํ•œ Call ๊ฐ์ฒด ๋ฆฌํ„ด (์ œ๋„ค๋ฆญ ํƒ€์ž…์— DTO ํด๋ž˜์Šค ์ง€์ •)
interface INetworkService {
	@GET("api/users")
	fun getUserList(@Query("page") page: String): Call<UserListModel>
}

๋ ˆํŠธ๋กœํ• ๊ฐ์ฒด ์ƒ์„ฑ

  • Retrofit์˜ ์ดˆ๊ธฐ ์„ค์ •์„ ๋ชฉ์ ์œผ๋กœ ํ•œ๋‹ค. (์•ฑ ์‹คํ–‰ ์‹œ ์ตœ์ดˆ์˜ ํ•œ๋ฒˆ๋งŒ ์„ค์ •)
  • baseUrl() ํ•จ์ˆ˜๋กœ ์„œ๋ฒ„ ์—ฐ๋™์„ ์œ„ํ•œ URL ์„ค์ •
  • addConverterFactory() ํ•จ์ˆ˜๋กœ JSON์ด๋‚˜ XML ๋ฐ์ดํ„ฐ๋ฅผ DTO ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜์‹œ์ผœ์ฃผ๋Š” converter ์ง€์ •
val retrofit: Retrofit
	get() = Retrofit.Builder()
		.baseUrl("https://reqres.in/")
		.addConverterFactory(GsonConverterFactory.create())
		.build()

์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„ ๊ฐ์ฒด ์ƒ์„ฑ

  • ๋ ˆํŠธ๋กœํ• ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด ์„œ๋น„์Šค ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค์˜ ๊ฐ์ฒด ํš๋“
var networkService: INetworkService = retrofit.create(INetworkService::class.java)

๋„คํŠธ์›Œํ‚น

  • ์ธํ„ฐํŽ˜์ด์Šค์— ์ •์˜๋œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ Call ๊ฐ์ฒด ๋ฆฌํ„ด ๋ฐ›๊ธฐ
  • Call ๊ฐ์ฒด์˜ enqueue ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์„œ๋ฒ„์™€์˜ ๋„คํŠธ์›Œํ‚น ์ง„ํ–‰
val userListCall = networkService.getUserList("1")

userListCall.enqueue(object : Callback<UserListModel> {
	override fun onResponse(call: Call<UserListModel>, response: Response<UserListModel>) {
		val userList = response.body()
	}
    
	override fun onFailure(call: Call<UserListModel>, t: Throwable) {
		call.cancel()
	}
})

์‹ค์Šต ์˜ˆ์ œ

์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๊ฒƒ์€ ์ด ์‚ฌ์ดํŠธ๋ฅผ ์ด์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ ํ•ด๋ณผ ์˜ˆ์ •์ด๋‹ค.

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ dependency ์ถ”๊ฐ€

๋ชจ๋“ˆ ๋‹จ์œ„์˜ build.gradle ํŒŒ์ผ

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

ํผ๋ฏธ์…˜ ๋ถ€์—ฌ

AndroidManifest.xml ํŒŒ์ผ

<uses-permission android:name="android.permission.INTERNET"/>

๋ ˆ์ด์•„์›ƒ ๊ตฌ์„ฑ

<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/listView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

UserModel.kt

package com.tutorial.c87

import com.google.gson.annotations.SerializedName

data class UserModel (
    @SerializedName("first_name")
    var firstName: String,
    @SerializedName("last_name")
    var lastName: String
)

UserListModel.kt

package com.tutorial.c87

data class UserListModel (
    var data: List<UserModel>?
)

INetworkService.kt

package com.tutorial.c87

import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query

interface INetworkService {
    @GET("api/users")
    fun getUserList(@Query("page") page: String): Call<UserListModel>
}

MainActivity.kt

<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/listView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
package com.tutorial.c87

import android.os.Bundle
import android.widget.ListView
import android.widget.SimpleAdapter
import androidx.appcompat.app.AppCompatActivity
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

class MainActivity : AppCompatActivity() {
    private val retrofit: Retrofit
        get() = Retrofit.Builder()
            .baseUrl("https://reqres.in/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val listView = findViewById<ListView>(R.id.listView)
        val networkService = retrofit.create(INetworkService::class.java)
        val call = networkService.getUserList("1")

        call.enqueue(object: Callback<UserListModel> {
            override fun onResponse(call: Call<UserListModel>, response: Response<UserListModel>) {
                val userList = response.body()
                val mutableList = mutableListOf<Map<String, String>>()
                userList?.data?.forEach {
                    val map = mapOf("firstName" to it.firstName, "lastName" to it.lastName)
                    mutableList.add(map)
                }
                val adapter = SimpleAdapter(
                    this@MainActivity,
                    mutableList,
                    android.R.layout.simple_expandable_list_item_2,
                    arrayOf("firstName", "lastName"),
                    intArrayOf(android.R.id.text1, android.R.id.text2)
                )
                listView.adapter = adapter
            }

            override fun onFailure(call: Call<UserListModel>, t: Throwable) {
                call.cancel()
            }
        })
    }
}


Glide๋กœ ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ

  • ๊ตฌ๊ธ€์—์„œ ๋งŒ๋“  ์ด๋ฏธ์ง€ ํ•ธ๋“ค๋ง์„ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • ๋ฆฌ์†Œ์Šค ์ด๋ฏธ์ง€, ํŒŒ์ผ ์ด๋ฏธ์ง€, ๋„คํŠธ์›Œํฌ ์ด๋ฏธ์ง€ ํš๋“
  • ์ด๋ฏธ์ง€์˜ ํฌ๊ธฐ ์กฐ์ • (OOM, OutOfMemory ๋ฌธ์ œ ๋ฐฉ์ง€)
  • ๋กœ๋”ฉ ๋ฐ ์—๋Ÿฌ ์ด๋ฏธ์ง€ ํ‘œ์‹œ

cf) ๋ ˆํŠธ๋กœํ•์œผ๋กœ๋„ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์ด๋ฏธ์ง€๋ฅผ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ, Glide์™€ ๊ฐ™์€ ์ด๋ฏธ์ง€๋ฅผ ์œ„ํ•œ ์ „๋ฌธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ํ›จ์”ฌ ํŽธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ๋ฒ•์„ ์•Œ์•„๋ณด์ž!

implementation 'com.github.bumptech.glide:glide:4.11.0'
  • ImageView์— ์ด๋ฏธ์ง€ ์ถœ๋ ฅ
Glide.with(this)
	.load(R.drawable.seoul) // ๋ฆฌ์†Œ์Šค ์ด๋ฏธ์ง€ 
	.into(resultView)
Glide.with(this)
	.load(url) // ์„œ๋ฒ„ ์ด๋ฏธ์ง€ 
	.into(resultView)
  • ํŠน์ • ํฌ๊ธฐ๋กœ ์ด๋ฏธ์ง€ ๋กœ๋”ฉ
Glide.with(this)
	.load(R.drawable.seoul)
	.override(200, 200) // ์‚ฌ์ด์ฆˆ ์ง€์ • 
	.into(resultView)
  • ๋กœ๋”ฉ ๋ฐ ์—๋Ÿฌ ์ด๋ฏธ์ง€ ์ถœ๋ ฅ
Glide.with(this)
	.load(url) // ์„œ๋ฒ„ ์ด๋ฏธ์ง€ 
	.override(200, 200)
	.placeholder(R.drawable.loading) // ๋กœ๋”ฉ ์ด๋ฏธ์ง€ 
	.error(R.drawable.error) // ์—๋Ÿฌ ์ด๋ฏธ์ง€ 
	.into(resultView)

์‹ค์Šต ์˜ˆ์ œ

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์˜์กด์„ฑ ์ถ”๊ฐ€

implementation 'com.github.bumptech.glide:glide:4.11.0'

ํผ๋ฏธ์…˜ ๋ถ€์—ฌ

<uses-permission android:name="android.permission.INTERNET"/>

MainActivity.kt

package com.tutorial.c88

import android.os.Bundle
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import com.bumptech.glide.Glide

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val resultView = findViewById<ImageView>(R.id.resultView)

        Glide.with(this)
            .load("https://www.edigitalagency.com.au/wp-content/uploads/google-logo-png-transparent-background-large-new.png")
            .override(200, 200)
            .placeholder(R.drawable.loading)
            .error(R.drawable.error)
            .into(resultView)
    }
}

์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋œ ๊ฒฝ์šฐ

URL ์ฃผ์†Œ๊ฐ€ ์ž˜๋ชป๋œ ๊ฒฝ์šฐ

profile
์Šต๊ด€์ด ๋  ๋•Œ๊นŒ์ง€ ๐Ÿ“

0๊ฐœ์˜ ๋Œ“๊ธ€