0Pricing
Android Academy · บทเรียน

การโหลดรูปภาพด้วย Coil

การโหลดรูปภาพแบบอะซิงโครนัสใน Compose

การโหลดรูปภาพด้วย Coil เป็นบทเรียน Android Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Android Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Android Academy มีบทเรียนทั้งหมด 4 บทเรียน

เหตุผลที่ต้องใช้ตัวโหลดรูปภาพ

แอปสมัยใหม่ส่วนใหญ่แสดงรูปภาพจากอินเทอร์เน็ต เช่น รูปโปรไฟล์ รูปสินค้า และภาพขนาดย่อของบทความ การดาวน์โหลดและถอดรหัสรูปภาพเหล่านั้นอย่างถูกต้องทำได้ยากกว่าที่คิด

คุณต้องดึงข้อมูลไบต์ผ่านเครือข่ายในเธรดเบื้องหลัง ถอดรหัสเป็นบิตแมป แคชไว้เพื่อไม่ต้องดึงซ้ำ และยกเลิกคำขอเมื่อผู้ใช้เลื่อนผ่านไปแล้ว การเขียนทั้งหมดนี้เองมีโอกาสเกิดข้อผิดพลาดได้ง่าย

Coil (Coroutine Image Loader) จัดการทั้งหมดนี้ให้คุณด้วย API ขนาดเล็กที่เหมาะกับ Compose ในบทเรียนนี้ คุณจะโหลดรูปภาพระยะไกลรูปแรก

การเพิ่ม Coil ในโปรเจ็กต์

Coil เผยแพร่ในรูปแบบการพึ่งพา Gradle สำหรับ Jetpack Compose ให้ใช้อาร์ทิแฟกต์ coil-compose ซึ่งมาพร้อมคอมโพสิเบิล AsyncImage

เพิ่มอาร์ทิแฟกต์นี้ใน build.gradle.kts ของมอดูล Coil 3 เป็นเวอร์ชันหลักปัจจุบันและทำงานได้ข้ามแพลตฟอร์ม ส่วนการผสานรวมกับ Compose คือสิ่งที่เราใช้ในบทเรียนนี้

// build.gradle.kts (module level)
dependencies {
    implementation("io.coil-kt.coil3:coil-compose:3.0.4")
    implementation("io.coil-kt.coil3:coil-network-okhttp:3.0.4")
}

สิทธิ์อินเทอร์เน็ต

หากต้องการดาวน์โหลดรูปภาพจาก URL แอปของคุณต้องมีสิทธิ์ INTERNET สิทธิ์นี้เป็นสิทธิ์ปกติที่ขอเมื่อติดตั้งแอป ดังนั้นจึงประกาศไว้ในไฟล์แม Manifest เท่านั้น ไม่มีกล่องโต้ตอบขอสิทธิ์ขณะรัน

หากไม่มีสิทธิ์นี้ คำขอเครือข่ายทุกคำขอจะล้มเหลวด้วยข้อยกเว้นด้านความปลอดภัย

<!-- AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.INTERNET" />
    <application ...>
        ...
    </application>
</manifest>

AsyncImage แรกของคุณ

วิธีที่ง่ายที่สุดในการแสดงรูปภาพระยะไกลใน Compose คือ AsyncImage ส่งค่า model ซึ่งโดยปกติเป็นสตริง URL และ contentDescription ให้กับคอมโพสิเบิล แล้ว Coil จะจัดการส่วนที่เหลือ ทั้งการดึงข้อมูลเบื้องหลัง การถอดรหัส และการแสดงผล

ระบบจะใช้คอร์รูทีนที่ผูกกับคอมโพสิชันโดยอัตโนมัติ ดังนั้นคำขอจะถูกยกเลิกหากคอมโพสิเบิลออกจากหน้าจอ

import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage

@Composable
fun Avatar() {
    AsyncImage(
        model = "https://example.com/avatar.png",
        contentDescription = "User avatar",
        modifier = Modifier.size(96.dp)
    )
}

contentScale: การจัดวางรูปภาพ

รูปภาพมักมีขนาดไม่ตรงกับช่องวางในเลย์เอาต์ของคุณพอดี ContentScale ใช้ควบคุมการปรับขนาดบิตแมปภายในขอบเขตของช่อง

  • ContentScale.Crop เติมเต็มกล่องและตัดส่วนที่เกินออก เหมาะสำหรับรูปประจำตัวและภาพขนาดย่อ
  • ContentScale.Fit แสดงรูปภาพทั้งหมด แต่อาจเหลือพื้นที่ว่าง
  • ContentScale.FillBounds ยืดรูปให้เต็มพื้นที่ ซึ่งอาจทำให้รูปผิดสัดส่วน

Crop เป็นตัวเลือกที่ใช้บ่อยที่สุดสำหรับช่องขนาดตายตัว

import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage

@Composable
fun CircleAvatar(url: String) {
    AsyncImage(
        model = url,
        contentDescription = "Avatar",
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(80.dp)
            .clip(CircleShape)
    )
}

การสร้างคำขอด้วย ImageRequest

การส่งสตริง URL เป็นวิธีที่รวดเร็ว หากต้องการควบคุมมากขึ้น ให้สร้าง ImageRequest วิธีนี้ช่วยให้คุณตั้งค่าตัวเลือกต่าง ๆ เช่น การเฟดข้าม ส่วนหัว การแปลง และคีย์แคช

คุณต้องใช้ Context ซึ่ง Compose จัดเตรียมให้ผ่าน LocalContext.current

import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import coil3.request.crossfade

@Composable
fun ProductImage(url: String) {
    val context = LocalContext.current
    val request = ImageRequest.Builder(context)
        .data(url)
        .crossfade(true)
        .build()

    AsyncImage(
        model = request,
        contentDescription = "Product photo"
    )
}

การเฟดข้ามเพื่อการโหลดที่ราบรื่น

โดยค่าเริ่มต้น รูปภาพจะแสดงขึ้นทันทีเมื่อโหลดเสร็จ ซึ่งอาจให้ความรู้สึกฉับพลัน crossfade(true) จะค่อย ๆ แสดงรูปภาพด้วยแอนิเมชันช่วงสั้น ๆ

คุณยังส่งระยะเวลาเป็นมิลลิวินาทีเพื่อให้การเฟดช้าหรือเร็วขึ้นได้ รายละเอียดเล็ก ๆ นี้ทำให้รายการต่าง ๆ ดูเรียบร้อยและลื่นไหลขึ้นมาก

import coil3.request.ImageRequest
import coil3.request.crossfade
import android.content.Context

fun smoothRequest(context: Context, url: String) =
    ImageRequest.Builder(context)
        .data(url)
        .crossfade(durationMillis = 300)
        .build()

การโหลดจากแหล่งต่าง ๆ

model ใน AsyncImage รองรับค่าได้หลากหลาย Coil โหลดจากแหล่งข้อมูลหลายประเภท ไม่ได้จำกัดเฉพาะ URL ระยะไกล:

  • String หรือ Uri สำหรับไฟล์บนเครือข่ายหรือในเครื่อง
  • รหัสทรัพยากร drawable (R.drawable.logo)
  • File จากอุปกรณ์
  • Uri ของเนื้อหาจากตัวเลือกรูปภาพ

ดังนั้นคอมโพสิเบิลเดียวกันจึงจัดการรูปภาพทั้งระยะไกลและในเครื่องได้อย่างราบรื่น

import android.net.Uri
import androidx.compose.runtime.Composable
import coil3.compose.AsyncImage

@Composable
fun FlexibleImage(source: Any) {
    // source can be a URL String, a Uri, a File, or a resource id
    AsyncImage(
        model = source,
        contentDescription = null
    )
}

// Examples:
// FlexibleImage("https://example.com/pic.jpg")
// FlexibleImage(Uri.parse("content://media/external/images/1"))

การตอบสนองต่อสถานะการโหลด

บางครั้งคุณต้องทราบว่ารูปภาพกำลังโหลด โหลดสำเร็จ หรือล้มเหลว เพื่อจะแสดง UI ที่แตกต่างกัน AsyncImagePainter เปิดเผยสถานะดังกล่าว แต่วิธีที่ง่ายที่สุดคือ SubcomposeAsyncImage ซึ่งให้คุณจัดเตรียมเนื้อหาสำหรับแต่ละสถานะได้

เราจะลงรายละเอียดเรื่องตัวแสดงระหว่างโหลดในบทเรียนถัดไป ส่วนบทนี้จะแนะนำโครงสร้างของการโหลดที่รับรู้สถานะ

import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.Composable
import coil3.compose.SubcomposeAsyncImage

@Composable
fun StatefulImage(url: String) {
    SubcomposeAsyncImage(
        model = url,
        contentDescription = "Photo",
        loading = { CircularProgressIndicator() }
    )
}

การยกเลิกที่จัดการให้อัตโนมัติ

ข้อดีสำคัญอย่างหนึ่งของ Coil คือการยกเลิกโดยอัตโนมัติ เนื่องจาก AsyncImage เริ่มคำขอภายในคอมโพสิชัน เมื่อคอมโพสิเบิลออกจากหน้าจอ เช่น แถวหนึ่งเลื่อนพ้น LazyColumn คำขอที่กำลังดำเนินการจะถูกยกเลิก

วิธีนี้ช่วยประหยัดแบนด์วิดท์และ CPU และป้องกันการทำงานที่สูญเปล่า คุณไม่ต้องเขียนโค้ดสำหรับการยกเลิกเอง จึงเป็นเหตุผลที่ Coil รองรับรายการยาว ๆ ได้ดี

import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage

@Composable
fun PhotoFeed(urls: List<String>) {
    LazyColumn {
        items(urls) { url ->
            AsyncImage(
                model = url,
                contentDescription = null,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(200.dp)
            )
        }
    }
}

การ์ดรูปภาพแบบสมบูรณ์

มารวมสิ่งที่เราเรียนรู้กัน: การ์ดที่มีรูปภาพระยะไกลเติมเต็มส่วนบน ใช้การเฟดข้าม และครอบรูปให้มีความสูงตายตัว นี่คือรูปแบบพื้นฐานที่คุณจะนำกลับมาใช้บ่อยครั้ง

import androidx.compose.foundation.layout.*
import androidx.compose.material3.Card
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import coil3.request.crossfade

@Composable
fun ImageCard(title: String, imageUrl: String) {
    val context = LocalContext.current
    Card(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
        Column {
            AsyncImage(
                model = ImageRequest.Builder(context)
                    .data(imageUrl)
                    .crossfade(true)
                    .build(),
                contentDescription = title,
                contentScale = ContentScale.Crop,
                modifier = Modifier.fillMaxWidth().height(180.dp)
            )
            Text(text = title, modifier = Modifier.padding(16.dp))
        }
    }
}

ตรวจสอบความเข้าใจ

คอมโพสิเบิลใดจาก coil-compose เป็นวิธีที่ง่ายที่สุดในการแสดงรูปภาพระยะไกลด้วย URL ใน Jetpack Compose

สรุป

คุณโหลดรูปภาพระยะไกลรูปแรกด้วย Coil แล้ว สิ่งสำคัญที่ควรจำ:

  • เพิ่ม coil-compose และการพึ่งพาเครือข่าย OkHttp รวมถึงสิทธิ์ INTERNET
  • AsyncImage(model = url, contentDescription = ...) คือวิธีที่รวดเร็ว
  • ใช้ ContentScale.Crop ร่วมกับขนาดตายตัวสำหรับรูปประจำตัวและภาพขนาดย่อ
  • สร้าง ImageRequest เมื่อต้องการการเฟดข้ามและการควบคุมเพิ่มเติม
  • Coil จะยกเลิกคำขอที่กำลังดำเนินการโดยอัตโนมัติเมื่อคอมโพสิเบิลออกจากหน้าจอ

ถัดไป: ทำให้การโหลดดูราบรื่นด้วยตัวแสดงระหว่างโหลดและสถานะข้อผิดพลาด

คำถามที่พบบ่อย

บทเรียน “การโหลดรูปภาพด้วย Coil” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การโหลดรูปภาพด้วย Coil” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Android Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Android Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การโหลดรูปภาพด้วย Coil”

การโหลดรูปภาพแบบอะซิงโครนัสใน Compose คุณปฏิบัติ Android Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Android Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Android Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “การโหลดรูปภาพด้วย Coil” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Android Academy นี้ได้ไหม

ได้ บทเรียน Android Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การโหลดรูปภาพด้วย Coil
  2. ตัวแทนและสถานะข้อผิดพลาด
  3. การแคชและประสิทธิภาพ
  4. การเล่นเสียงและวิดีโอ
← กลับไปที่ Android Academy