Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Arsitektur CameraX

CameraX adalah tambahan untuk Jetpack yang mempermudah pemanfaatan kapabilitas Camera2 API. Topik ini mencakup arsitektur CameraX, termasuk strukturnya, cara menggunakan API ini, cara menggunakan siklus proses, dan cara menggabungkan kasus penggunaan.

Struktur CameraX

Developer menggunakan CameraX untuk berinteraksi dengan kamera perangkat melalui abstraksi yang disebut kasus penggunaan. Kasus penggunaan berikut tersedia saat ini:

  • Pratinjau: menerima permukaan untuk menampilkan pratinjau, seperti PreviewView.
  • Analisis gambar: menyediakan buffer yang dapat diakses CPU untuk analisis, misalnya untuk machine learning
  • Pengambilan gambar: mengambil dan menyimpan foto

Kasus penggunaan dapat digabungkan dan aktif bersamaan. Misalnya, sebuah aplikasi dapat mengizinkan pengguna untuk menampilkan gambar yang dilihat kamera menggunakan kasus penggunaan pratinjau, memiliki kasus penggunaan analisis gambar yang menentukan apakah orang-orang dalam foto tersenyum, dan mencakup kasus penggunaan pengambilan gambar untuk mengambil gambar saat orang-orang tersebut tersenyum.

Model API

Untuk menggunakan library ini, Anda harus menentukan hal berikut:

  • Kasus penggunaan yang diinginkan dengan opsi konfigurasi.
  • Apa yang akan dilakukan dengan data output dengan menambahkan pemroses.
  • Alur yang diinginkan, seperti kapan mengaktifkan kamera dan kapan menghasilkan data, dengan menggabungkan kasus penggunaan ke Siklus Proses Arsitektur Android.

Anda mengonfigurasi kasus penggunaan menggunakan metode set() dan menyelesaikannya dengan metode build(). Setiap objek kasus penggunaan menyediakan sekumpulan API khusus kasus penggunaan. Misalnya, kasus penggunaan tangkapan gambar menyediakan pemanggilan metode takePicture().

Aplikasi bukan menempatkan mulai spesifik dan menghentikan panggilan metode di onResume() dan onPause(), tetapi aplikasi menentukan siklus proses untuk mengaitkan kamera dengan, menggunakan cameraProvider.bindToLifecycle(). Siklus proses tersebut selanjutnya memberi tahu CameraX kapan harus mengonfigurasi sesi pengambilan gambar dan memastikan kamera berubah ke status yang tepat untuk menyesuaikan dengan peralihan siklus proses.

Untuk langkah-langkah implementasi untuk setiap kasus penggunaan, lihat Mengimplementasikan pratinjau, Analisis gambar, dan Tangkapan gambar.

Contoh model API

Kasus penggunaan pratinjau berinteraksi dengan Surface untuk tampilan. Aplikasi membuat kasus penggunaan ini dengan opsi konfigurasi menggunakan kode berikut:

Kotlin

    val preview = Preview.Builder().build()
    val viewFinder: PreviewView = findViewById(R.id.previewView)

    // The use case is bound to an Android Lifecycle with the following code
    val camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)

    // PreviewView creates a surface provider and is the recommended provider
    preview.setSurfaceProvider(viewFinder.createSurfaceProvider(camera.cameraInfo))
    

Java

    Preview preview = new Preview.Builder().build();
    PreviewView viewFinder = findViewById(R.id.view_finder);

    // The use case is bound to an Android Lifecycle with the following code
    Camera camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview);

    // PreviewView creates a surface provider, using a Surface from a different
    // kind of view will require you to implement your own surface provider.
    preview.previewSurfaceProvider = viewFinder.createSurfaceProvider(camera.getCameraInfo());
    

Untuk kode contoh lainnya, lihat aplikasi contoh CameraX resmi.

Siklus proses CameraX

CameraX mengamati siklus proses untuk menentukan kapan harus membuka kamera, memulai sesi pengambilan gambar, serta kapan harus berhenti dan menutup kamera. API kasus penggunaan menyediakan panggilan metode dan callback untuk memantau progres.

Seperti dijelaskan dalam Menggabungkan kasus penggunaan, Anda dapat menggabungkan beberapa campuran kasus penggunaan menjadi satu siklus proses. Saat aplikasi Anda perlu mendukung kasus penggunaan yang tidak dapat digabung, Anda dapat melakukan salah satu langkah berikut:

  • Mengelompokkan kasus penggunaan yang kompatibel bersama-sama menjadi beberapa fragmen, lalu beralih di antara fragmen
  • Membuat komponen siklus proses kustom dan menggunakannya untuk mengontrol siklus proses kamera secara manual

Jika Anda memisahkan tampilan dan LifecycleOwner kasus penggunaan kamera (misalnya, jika Anda menggunakan siklus proses kustom atau mempertahankan fragmen ), Anda harus memastikan bahwa semua kasus penggunaan tidak terikat dari CameraX dengan menggunakan CameraX.unbindAll() atau dengan membongkar setiap kasus penggunaan satu per satu. Atau, saat Anda melakukan binding kasus penggunaan ke Lifecycle, Anda dapat mengizinkan CameraX mengelola pembukaan dan menutup sesi pengambilan gambar dan memisahkan kasus penggunaan.

Jika semua fungsi kamera Anda sesuai dengan siklus proses komponen tunggal berbasis siklus proses seperti AppCompatActivity atau fragmen AppCompat, maka penggunaan siklus proses komponen tersebut saat menggabungkan semua kasus penggunaan yang diinginkan akan memastikan bahwa fungsionalitas kamera siap ketika komponen berbasis siklus proses aktif, dan dibuang dengan aman, sehingga tidak menghabiskan resource apa pun.

LifecycleOwner kustom

Untuk kasus lanjutan, Anda dapat membuat penyesuaian LifecycleOwner untuk memungkinkan aplikasi mengontrol siklus sesi CameraX secara eksplisit, bukan mengikatnya ke Android standar LifecycleOwner.

Contoh kode berikut menunjukkan cara membuat LifecycleOwner kustom sederhana:

Kotlin

    class CustomLifecycle : LifecycleOwner {
        private val lifecycleRegistry: LifecycleRegistry

        init {
            lifecycleRegistry = LifecycleRegistry(this);
            lifecycleRegistry.markState(Lifecycle.State.CREATED)
        }
        ...
        fun doOnResume() {
            lifecycleRegistry.markState(State.RESUMED)
        }
        ...
        override fun getLifecycle(): Lifecycle {
            return lifecycleRegistry
        }
    }
    

Java

    public class CustomLifecycle implements LifecycleOwner {
        private LifecycleRegistry lifecycleRegistry;
        public CustomLifecycle() {
            lifecycleRegistry = new LifecycleRegistry(this);
            lifecycleRegistry.markState(Lifecycle.State.CREATED);
        }
       ...
       public void doOnResume() {
            lifecycleRegistry.markState(State.RESUMED);
        }
       ...
        public Lifecycle getLifecycle() {
            return lifecycleRegistry;
        }
    }
    

Dengan menggunakan LifecycleOwner ini, aplikasi Anda dapat melakukan transisi status pada poin yang diinginkan dalam kodenya. Untuk informasi selengkapnya tentang cara mengimplementasikan fungsi ini pada aplikasi Anda, lihat Mengimplementasikan LifecycleOwner kustom.

Kasus penggunaan serentak

Kasus penggunaan dapat berjalan secara serentak. Meskipun kasus penggunaan dapat secara berurutan terikat ke siklus proses, lebih baik untuk melakukan binding semua kasus penggunaan dengan satu panggilan ke CameraProcessProvider.bindToLifecycle(). Untuk informasi selengkapnya tentang praktik terbaik perubahan konfigurasi, lihat Menangani perubahan konfigurasi.

Dalam contoh kode berikut, aplikasi menentukan dua kasus penggunaan yang akan dibuat dan dijalankan secara bersamaan. Aplikasi juga menentukan siklus proses yang digunakan untuk kedua kasus penggunaan, sehingga keduanya dimulai dan dihentikan sesuai dengan siklus prosesnya.

Kotlin

    private lateinit var imageCapture: ImageCapture

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

        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

        cameraProviderFuture.addListener(Runnable {
            // Camera provider is now guaranteed to be available
            val cameraProvider = cameraProviderFuture.get()

            // Set up the preview use case to display camera preview.
            val preview = Preview.Builder().build()

            // Set up the capture use case to allow users to take photos.
            imageCapture = ImageCapture.Builder()
                    .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                    .build()

            // Choose the camera by requiring a lens facing
            val cameraSelector = CameraSelector.Builder()
                    .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
                    .build()

            // Attach use cases to the camera with the same lifecycle owner
            val camera = cameraProvider.bindToLifecycle(
                    this as LifecycleOwner, cameraSelector, preview, imageCapture)

            // Connect the preview use case to the previewView
            preview.setSurfaceProvider(
                    previewView.createSurfaceProvider(camera.cameraInfo))
        }, ContextCompat.getMainExecutor(this))
    }
    

Java

    private ImageCapture imageCapture;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        PreviewView previewView = findViewById(R.id.previewView);

        ListenableFuture cameraProviderFuture =
                ProcessCameraProvider.getInstance(this);

        cameraProviderFuture.addListener(() -> {
            try {
                // Camera provider is now guaranteed to be available
                ProcessCameraProvider cameraProvider = cameraProviderFuture.get();

                // Set up the view finder use case to display camera preview
                Preview preview = new Preview.Builder().build();

                // Set up the capture use case to allow users to take photos
                imageCapture = new ImageCapture.Builder()
                        .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                        .build();

                // Choose the camera by requiring a lens facing
                CameraSelector cameraSelector = new CameraSelector.Builder()
                        .requireLensFacing(lensFacing)
                        .build();

                // Attach use cases to the camera with the same lifecycle owner
                Camera camera = cameraProvider.bindToLifecycle(
                        ((LifecycleOwner) this),
                        cameraSelector,
                        preview,
                        imageCapture);

                // Connect the preview use case to the previewView
                preview.setSurfaceProvider(
                        previewView.createSurfaceProvider(camera.getCameraInfo()));
            } catch (InterruptedException | ExecutionException e) {
                // Currently no exceptions thrown. cameraProviderFuture.get() should
                // not block since the listener is being called, so no need to
                // handle InterruptedException.
            }
        }, ContextCompat.getMainExecutor(this));
    }
    

Kombinasi konfigurasi berikut ini didukung:

Pratinjau Analisis Pengambilan gambar Menggabungkan kasus penggunaan
Memberikan pratinjau kepada pengguna, mengambil foto, dan menganalisis aliran gambar.
  Mengambil foto dan menganalisis aliran gambar.
  Memberikan pratinjau dengan efek visual yang diterapkan berdasarkan analisis atas gambar yang sedang dialirkan.
  Menampilkan apa yang dilihat kamera dan mengambil foto sesuai tindakan pengguna.

Saat ekstensi diaktifkan, hanya ImageCapture dan Preview yang dijamin. Bergantung pada implementasi OEM, Anda juga mungkin tidak dapat menggunakan ImageAnalysis.

ImageCapture tidak berfungsi sendiri, meskipun Preview dan ImageAnalysis bisa.

Izin

Aplikasi Anda membutuhkan izin CAMERA. Untuk menyimpan gambar ke file, tindakan ini juga memerlukan izin WRITE_EXTERNAL_STORAGE, kecuali pada perangkat yang menjalankan Android 10 atau yang lebih baru.

Untuk informasi selengkapnya tentang mengonfigurasi izin untuk aplikasi Anda, baca Meminta Izin Aplikasi.

Persyaratan

CameraX memiliki persyaratan versi minimum berikut:

  • Android API level 21
  • Komponen Arsitektur Android 1.1.1

Untuk aktivitas berbasis siklus proses, gunakan FragmentActivity atau AppCompatActivity.

Mendeklarasikan dependensi

Untuk menambahkan dependensi pada CameraX, Anda harus menambahkan repositori Google Maven ke project Anda.

Buka file build.gradle untuk project Anda dan tambahkan repositori google() seperti yang ditunjukkan berikut:

    allprojects {
        repositories {
            google()
            jcenter()
        }
    }
    

Tambahkan item berikut ke bagian akhir blok Android:

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    

Tambahkan kode berikut ke file build.gradle setiap modul untuk aplikasi:

dependencies {
  // CameraX core library using the camera2 implementation
  def camerax_version = "1.0.0-beta10"
  // The following line is optional, as the core library is included indirectly by camera-camera2
  implementation "androidx.camera:camera-core:${camerax_version}"
  implementation "androidx.camera:camera-camera2:${camerax_version}"
  // If you want to additionally use the CameraX Lifecycle library
  implementation "androidx.camera:camera-lifecycle:${camerax_version}"
  // If you want to additionally use the CameraX View class
  implementation "androidx.camera:camera-view:1.0.0-alpha17"
  // If you want to additionally use the CameraX Extensions library
  implementation "androidx.camera:camera-extensions:1.0.0-alpha17"
}

Untuk informasi selengkapnya tentang cara mengonfigurasi aplikasi agar sesuai dengan persyaratan ini, lihat Mendeklarasikan dependensi.

Referensi lainnya

Untuk mempelajari CameraX lebih lanjut, lihat referensi tambahan berikut.

Codelab

  • Memulai CameraX
  • Contoh kode

  • Contoh aplikasi CameraX resmi