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

การแสดงตัวอย่างจากกล้อง

เชื่อมต่อภาพตัวอย่างแบบสด

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

เป้าหมาย: ภาพตัวอย่างแบบสด

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

คุณจะผสานสามส่วนเข้าด้วยกัน ได้แก่ PreviewView กรณีการใช้งาน Preview และ ProcessCameraProvider ที่เชื่อมไว้

การขอสิทธิ์ใช้กล้อง

ก่อนจะแสดงภาพตัวอย่างได้ คุณต้องได้รับสิทธิ์จากผู้ใช้ก่อน ใน Compose Accompanist (หรือ API สิทธิ์อย่างเป็นทางการ) ช่วยให้ทำได้ง่ายด้วย rememberPermissionState

เริ่มกล้องหลังจากสิทธิ์เป็น granted แล้วเท่านั้น

@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun CameraScreen() {
    val permission = rememberPermissionState(Manifest.permission.CAMERA)

    LaunchedEffect(Unit) { permission.launchPermissionRequest() }

    if (permission.status.isGranted) {
        CameraPreview()
    } else {
        Text("Camera permission is required.")
    }
}

การฝัง PreviewView ใน Compose

PreviewView เป็น Android View แบบดั้งเดิม ดังนั้นคุณจึงโฮสต์ไว้ภายใน Compose ด้วย AndroidView แลมบ์ดา factory จะสร้างมุมมองขึ้นครั้งเดียวและมอบการอ้างอิงให้คุณนำไปกำหนดค่า

เก็บมุมมองที่สร้างขึ้นไว้ เพื่อให้คุณเชื่อมพื้นที่แสดงผลของกล้องเข้ากับมุมมองนั้นได้

@Composable
fun CameraPreview(modifier: Modifier = Modifier) {
    AndroidView(
        modifier = modifier.fillMaxSize(),
        factory = { context ->
            PreviewView(context).apply {
                scaleType = PreviewView.ScaleType.FILL_CENTER
            }
        }
    )
}

การรับ LifecycleOwner

หากต้องการเชื่อมกล้อง คุณต้องมี LifecycleOwner ใน Compose คุณอ่านค่าปัจจุบันด้วย LocalLifecycleOwner.current และอ่านบริบทด้วย LocalContext.current

ต้องใช้ทั้งสองรายการเพื่อเตรียม provider ของกล้องและเชื่อมกรณีการใช้งาน

val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current

การสร้างกรณีการใช้งาน Preview

กรณีการใช้งาน Preview จะส่งเฟรมไปยังพื้นที่แสดงผล หลังจากสร้างแล้ว ให้เชื่อมเข้ากับ PreviewView โดยเรียก setSurfaceProvider พร้อม provider ของพื้นที่แสดงผลจากมุมมอง

การเชื่อมนี้ทำให้ภาพจากกล้องปรากฏบนหน้าจอจริง

val preview = Preview.Builder().build()
preview.setSurfaceProvider(previewView.surfaceProvider)

การเชื่อมภายในคอร์รูทีน

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

LaunchedEffect(previewView) {
    val cameraProvider = ProcessCameraProvider.getInstance(context).await()
    val preview = Preview.Builder().build().also {
        it.setSurfaceProvider(previewView.surfaceProvider)
    }
    cameraProvider.unbindAll()
    cameraProvider.bindToLifecycle(
        lifecycleOwner,
        CameraSelector.DEFAULT_BACK_CAMERA,
        preview
    )
}

ส่วนขยาย await()

ProcessCameraProvider.getInstance() คืนค่าเป็น ListenableFuture ส่วนขยาย await() จาก kotlinx-coroutines-guava จะระงับการทำงานจนกว่าค่าจะพร้อม ทำให้โค้ดแบบเรียกกลับกลายเป็นโค้ดลำดับขั้นที่อ่านง่าย

เพิ่มส่วนพึ่งพา org.jetbrains.kotlinx:kotlinx-coroutines-guava เพื่อใช้งานส่วนขยายนี้

import kotlinx.coroutines.guava.await

// Without await you'd use a listener:
// future.addListener({ val provider = future.get() }, executor)
// await() makes it a single suspend call instead.

การประกอบทุกอย่างเข้าด้วยกัน

นี่คือ composable สำหรับภาพตัวอย่างฉบับสมบูรณ์ สังเกตลำดับการทำงาน: สร้าง PreviewView ใน factory เก็บการอ้างอิงไว้ แล้วจึงเชื่อมภายใน LaunchedEffect

@Composable
fun CameraPreview(modifier: Modifier = Modifier) {
    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current
    val previewView = remember { PreviewView(context) }

    LaunchedEffect(previewView) {
        val provider = ProcessCameraProvider.getInstance(context).await()
        val preview = Preview.Builder().build().also {
            it.setSurfaceProvider(previewView.surfaceProvider)
        }
        provider.unbindAll()
        provider.bindToLifecycle(
            lifecycleOwner,
            CameraSelector.DEFAULT_BACK_CAMERA,
            preview
        )
    }

    AndroidView(
        factory = { previewView },
        modifier = modifier.fillMaxSize()
    )
}

ประเภทการปรับขนาด

อัตราส่วนภาพของเซนเซอร์กล้องแทบไม่ตรงกับหน้าจอของคุณ PreviewView.ScaleType ควบคุมวิธีที่ภาพจากกล้องจะพอดีกับมุมมอง:

  • FILL_CENTER — เติมเต็มมุมมองโดยตัดขอบออก (ใช้บ่อยที่สุด)
  • FIT_CENTER — แสดงทั้งเฟรมพร้อมแถบดำ

เลือก FILL_CENTER สำหรับกล้องเต็มหน้าจอที่ให้ความรู้สึกเต็มอิ่ม

previewView.scaleType = PreviewView.ScaleType.FILL_CENTER
// or
previewView.scaleType = PreviewView.ScaleType.FIT_CENTER

การสลับกล้อง

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

var selector by remember { mutableStateOf(CameraSelector.DEFAULT_BACK_CAMERA) }

LaunchedEffect(selector) {
    val provider = ProcessCameraProvider.getInstance(context).await()
    provider.unbindAll()
    provider.bindToLifecycle(lifecycleOwner, selector, preview)
}

// Flip button toggles 'selector' between front and back.

ข้อผิดพลาดที่พบบ่อย

ข้อผิดพลาดสองอย่างทำให้ภาพตัวอย่างเป็นสีดำ:

  • ลืมเรียก setSurfaceProvider — เฟรมไม่มีปลายทางให้ส่งไป
  • ไม่เรียก unbindAll() ก่อนเชื่อมใหม่ — CameraX จะแจ้งข้อผิดพลาดหากกรณีการใช้งานถูกเชื่อมไว้สองครั้ง

โปรดจำไว้ด้วยว่า ภาพตัวอย่างจะไม่เริ่มจนกว่าจะได้รับสิทธิ์จริง

ตรวจสอบอย่างรวดเร็ว

ตรวจสอบความเข้าใจเกี่ยวกับการเชื่อมต่อภาพตัวอย่าง

สรุปทบทวน

คุณสร้างภาพตัวอย่างจากกล้องแบบสดใน Compose แล้ว:

  • ขอสิทธิ์ CAMERA ก่อนเริ่มทำงาน
  • โฮสต์ PreviewView ด้วย AndroidView
  • รอ ProcessCameraProvider ภายในคอร์รูทีน
  • สร้าง Preview เรียก setSurfaceProvider เรียก unbindAll() แล้วจึงเรียก bindToLifecycle

ถัดไป คุณจะเพิ่มกรณีการใช้งาน ImageCapture และถ่ายภาพจริง

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

บทเรียน “การแสดงตัวอย่างจากกล้อง” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “การแสดงตัวอย่างจากกล้อง”

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

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

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

บทเรียน “การแสดงตัวอย่างจากกล้อง” ใช้เวลานานแค่ไหน

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

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

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

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

  1. ภาพรวม CameraX
  2. การแสดงตัวอย่างจากกล้อง
  3. การถ่ายภาพ
  4. การบันทึกวิดีโอ
← กลับไปที่ Android Academy