Trang này đề cập đến cấu trúc của CameraX, bao gồm cấu trúc, cách làm việc với API, cách làm việc với vòng đời và cách kết hợp các trường hợp sử dụng.
Cấu trúc CameraX
Bạn có thể sử dụng CameraX để giao tiếp với máy ảnh của thiết bị thông qua một giá trị trừu tượng được gọi là trường hợp sử dụng. Bạn có thể sử dụng các trường hợp sau:
- Xem trước: chấp nhận một nền tảng để hiển thị bản xem trước, chẳng hạn như
PreviewView
. - Phân tích hình ảnh: cung cấp vùng đệm mà CPU có thể truy cập để phân tích, chẳng hạn như cho công nghệ máy học.
- Chụp ảnh: chụp và lưu ảnh.
- Quay video: quay video và ghi âm bằng
VideoCapture
Các trường hợp sử dụng có thể được kết hợp và hoạt động đồng thời. Ví dụ: Một ứng dụng có thể cho phép người dùng xem hình ảnh mà máy ảnh thấy bằng trường hợp sử dụng xem trước, có trường hợp sử dụng phân tích hình ảnh xác định liệu những người trong ảnh có đang cười hay không và đưa vào một trường hợp sử dụng chụp ảnh để chụp ảnh khi mọi người đã sẵn sàng.
Mô hình API
Để làm việc với thư viện, bạn cần chỉ định những điều sau:
- Trường hợp sử dụng mong muốn với các tuỳ chọn cấu hình.
- Việc cần làm với dữ liệu đầu ra bằng cách đính kèm trình nghe.
- Quy trình dự kiến, chẳng hạn như thời điểm bật máy ảnh và thời điểm tạo dữ liệu, bằng cách liên kết trường hợp sử dụng với Vòng đời kiến trúc Android.
Bạn định cấu hình các trường hợp sử dụng bằng các phương thức set()
và hoàn tất các trường hợp sử dụng đó bằng phương thức build()
. Mỗi đối tượng trường hợp sử dụng cung cấp một tập hợp API dành riêng cho trường hợp sử dụng. Ví dụ: Trường hợp sử dụng chụp ảnh cung cấp lệnh gọi phương thức takePicture()
.
Thay vì thực hiện các lệnh gọi phương thức bắt đầu và dừng cụ thể trong onResume()
và onPause()
, ứng dụng này chỉ định vòng đời để liên kết máy ảnh bằng cách sử dụng cameraProvider.bindToLifecycle()
.
Sau đó, vòng đời thông báo cho CameraX về thời điểm cần định cấu hình phiên chụp ảnh và đảm bảo trạng thái của máy ảnh thay đổi phù hợp để khớp với các chuyển đổi vòng đời.
Để biết các bước triển khai cho từng trường hợp sử dụng, xem phần Triển khai bản xem trước, Phân tích hình ảnh, Chụp ảnh và Quay video
Ví dụ về mô hình API
Trường hợp sử dụng xem trước tương tác với một Surface
để hiển thị. Ứng dụng tạo trường hợp sử dụng với các tuỳ chọn cấu hình bằng mã sau:
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.getSurfaceProvider())
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.getSurfaceProvider();
Để biết thêm mã ví dụ, xem ứng dụng mẫu CameraX chính thức.
CameraX Lifecycle
CameraX theo dõi vòng đời để xác định thời điểm mở máy ảnh, thời điểm tạo phiên quay chụp, cũng như thời điểm dừng và tắt. API trường hợp sử dụng cung cấp các lệnh gọi phương thức và lệnh gọi lại để theo dõi tiến trình.
Như được giải thích trong phần Kết hợp các trường hợp sử dụng, bạn có thể liên kết một số danh sách kết hợp các trường hợp sử dụng với một vòng đời duy nhất. Khi ứng dụng của bạn cần hỗ trợ các trường hợp sử dụng không thể kết hợp được, bạn có thể thực hiện một trong những thao tác sau:
- Nhóm các trường hợp sử dụng tương thích lại với nhau thành nhiều mảnh, sau đó chuyển đổi giữa các mảnh
- Tạo một thành phần trong vòng đời tuỳ chỉnh và sử dụng thành phần đó để điều khiển vòng đời của máy ảnh theo cách thủ công
Nếu bạn tách riêng các chủ sở hữu Lifecycle của trường hợp sử dụng xem và máy ảnh (ví dụ: nếu bạn sử dụng vòng đời tuỳ chỉnh hoặc mảnh giữ lại), bạn phải đảm bảo rằng tất cả các trường hợp sử dụng huỷ liên kết với CameraX bằng cách sử dụng ProcessCameraProvider.unbindAll()
hoặc bằng cách huỷ liên kết từng trường hợp sử dụng một. Ngoài ra, khi liên kết các trường hợp sử dụng với Lifecycle, bạn có thể cho phép CameraX quản lý việc mở và đóng phiên quay chụp và huỷ liên kết các trường hợp sử dụng.
Nếu tất cả chức năng của máy ảnh tương ứng với vòng đời của một thành phần nhận biết vòng đời duy nhất, chẳng hạn như AppCompatActivity
hoặc một mảnh AppCompat
, thì việc sử dụng vòng đời của thành phần đó khi liên kết tất cả các trường hợp sử dụng mong muốn sẽ đảm bảo rằng chức năng của máy ảnh đã sẵn sàng khi thành phần nhận biết vòng đời hoạt động và được xử lý một cách an toàn, không tốn bất kỳ tài nguyên nào.
LifecycleOwner tuỳ chỉnh
Đối với các trường hợp nâng cao, bạn có thể tạo một LifecycleOwner
tuỳ chỉnh để cho phép ứng dụng của bạn kiểm soát rõ ràng vòng đời phiên CameraX thay vì liên kết với Android tiêu chuẩnLifecycleOwner
.
Mã mẫu sau đây trình bày cách tạo một LifecycleOwner tuỳ chỉnh đơn giản:
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; } }
Khi sử dụng LifecycleOwner
này, ứng dụng của bạn có thể đặt các lượt chuyển đổi trạng thái tại các điểm mong muốn trong mã. Để biết thêm thông tin về cách triển khai chức năng này trong ứng dụng của bạn, hãy xem phần Triển khai một LifecycleOwner tuỳ chỉnh.
Các trường hợp sử dụng đồng thời
Các trường hợp sử dụng có thể chạy đồng thời. Mặc dù các trường hợp sử dụng có thể được liên kết tuần tự với một vòng đời, nhưng bạn nên liên kết tất cả các trường hợp sử dụng bằng một lệnh gọi tới CameraProcessProvider.bindToLifecycle()
. Để biết thêm thông tin về các phương pháp hay nhất khi thay đổi cấu hình, xem phần Xử lý các thay đổi về cấu hình.
Trong mã mẫu sau, ứng dụng chỉ định hai trường hợp sử dụng cần được tạo và chạy đồng thời. Mã mẫu này cũng xác định vòng đời cần sử dụng cho cả hai trường hợp sử dụng, để cả hai đều bắt đầu và dừng theo vòng đời đó.
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.getSurfaceProvider()) }, 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<ProcessCameraProvider> 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.getSurfaceProvider()); } catch (InterruptedException | ExecutionException e) { // Currently no exceptions thrown. cameraProviderFuture.get() // shouldn't block since the listener is being called, so no need to // handle InterruptedException. } }, ContextCompat.getMainExecutor(this)); }
Chúng tôi đảm bảo hỗ trợ các tổ hợp cấu hình sau đây (khi yêu cầu trường hợp sử dụng Xem trước hoặc Quay video, nhưng không yêu cầu cả hai cùng một lúc):
Xem trước hoặc Quay video | Chụp ảnh | Phân tích | Mô tả |
---|---|---|---|
Cung cấp cho người dùng tính năng xem trước hoặc quay video, chụp ảnh và phân tích luồng hình ảnh. | |||
Chụp ảnh và phân tích luồng hình ảnh. | |||
Cung cấp cho người dùng tính năng xem trước hoặc quay video, chụp ảnh. | |||
Cung cấp cho người dùng tính năng xem trước hoặc quay video, cũng như phân tích luồng hình ảnh. |
Khi yêu cầu cả Xem trước và Quay video, các tổ hợp trường hợp sử dụng sau đây được hỗ trợ theo điều kiện:
Xem trước | Quay video | Chụp ảnh | Phân tích | Yêu cầu đặc biệt |
---|---|---|---|---|
Được đảm bảo cho tất cả máy ảnh | ||||
Thiết bị máy ảnh LIMITED (hoặc cao hơn). | ||||
Thiết bị máy ảnh LEVEL_3 (hoặc cao hơn). |
Ngoài ra,
- Mỗi trường hợp sử dụng đều có thể tự hoạt động. Ví dụ: Một ứng dụng có thể quay video mà không cần sử dụng tính năng xem trước.
- Khi các tiện ích được bật, chỉ tổ hợp
ImageCapture
vàPreview
được đảm bảo hoạt động. Tuỳ thuộc vào cách triển khai của OEM (Nhà sản xuất thiết bị gốc), bạn cũng có thể không thêm đượcImageAnalysis
; không thể bật tiện ích cho trường hợp sử dụngVideoCapture
. Xem Tài liệu tham khảo về tiện ích để biết thông tin chi tiết. - Tuỳ thuộc vào tính năng của máy ảnh, một số máy ảnh có thể hỗ trợ tổ hợp ở các chế độ độ phân giải thấp hơn nhưng không thể hỗ trợ sử dụng cùng một tổ hợp ở một số độ phân giải cao hơn.
Bạn có thể truy xuất cấp độ phần cứng được hỗ trợ từ Camera2CameraInfo
. Ví dụ: Mã sau đây kiểm tra xem máy ảnh mặt sau mặc định có phải là thiết bị LEVEL_3
không:
Kotlin
@androidx.annotation.OptIn(ExperimentalCamera2Interop::class) fun isBackCameraLevel3Device(cameraProvider: ProcessCameraProvider) : Boolean { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { return CameraSelector.DEFAULT_BACK_CAMERA .filter(cameraProvider.availableCameraInfos) .firstOrNull() ?.let { Camera2CameraInfo.from(it) } ?.getCameraCharacteristic(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3 } return false }
Java
@androidx.annotation.OptIn(markerClass = ExperimentalCamera2Interop.class) Boolean isBackCameraLevel3Device(ProcessCameraProvider cameraProvider) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { List\filteredCameraInfos = CameraSelector.DEFAULT_BACK_CAMERA .filter(cameraProvider.getAvailableCameraInfos()); if (!filteredCameraInfos.isEmpty()) { return Objects.equals( Camera2CameraInfo.from(filteredCameraInfos.get(0)).getCameraCharacteristic( CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL), CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3); } } return false; }
Quyền
Ứng dụng của bạn sẽ cần được cấp quyền CAMERA
. Để lưu hình ảnh vào tệp, bạn cũng cần có quyền WRITE_EXTERNAL_STORAGE
, ngoại trừ trên các thiết bị chạy Android 10 trở lên.
Để biết thêm thông tin về cách định cấu hình quyền cho ứng dụng của bạn, đọc bài viết Yêu cầu quyền cho ứng dụng.
Yêu cầu
CameraX có các yêu cầu tối thiểu về phiên bản sau đây:
- Android API cấp 21
- Bộ thành phần cấu trúc Android 1.1.1
Đối với các hoạt động nhận biết vòng đời, sử dụng FragmentActivity
hoặc AppCompatActivity
.
Khai báo phần phụ thuộc
Để thêm một phần phụ thuộc trên CameraX, bạn phải thêm kho lưu trữ Google Maven vào dự án.
Mở tệp settings.gradle
cho dự án của bạn và thêm kho lưu trữ google()
như trong mã sau:
Groovy
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } }
Kotlin
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } }
Thêm mã sau vào cuối khối lệnh Android:
Groovy
android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } // For Kotlin projects kotlinOptions { jvmTarget = "1.8" } }
Kotlin
android { compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } // For Kotlin projects kotlinOptions { jvmTarget = "1.8" } }
Thêm phần sau vào tệp build.gradle
của mỗi mô-đun cho một ứng dụng:
Groovy
dependencies { // CameraX core library using the camera2 implementation def camerax_version = "1.3.0-alpha04" // 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 VideoCapture library implementation "androidx.camera:camera-video:${camerax_version}" // If you want to additionally use the CameraX View class implementation "androidx.camera:camera-view:${camerax_version}" // If you want to additionally add CameraX ML Kit Vision Integration implementation "androidx.camera:camera-mlkit-vision:${camerax_version}" // If you want to additionally use the CameraX Extensions library implementation "androidx.camera:camera-extensions:${camerax_version}" }
Kotlin
dependencies { // CameraX core library using the camera2 implementation val camerax_version = "1.3.0-alpha04" // 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 VideoCapture library implementation("androidx.camera:camera-video:${camerax_version}") // If you want to additionally use the CameraX View class implementation("androidx.camera:camera-view:${camerax_version}") // If you want to additionally add CameraX ML Kit Vision Integration implementation("androidx.camera:camera-mlkit-vision:${camerax_version}") // If you want to additionally use the CameraX Extensions library implementation("androidx.camera:camera-extensions:${camerax_version}") }
Để biết thêm thông tin về cách định cấu hình ứng dụng của bạn nhằm tuân thủ các yêu cầu này, hãy xem bài viết Khai báo phần phụ thuộc.
Tài nguyên khác
Để tìm hiểu thêm về CameraX, hãy tham khảo các tài nguyên bổ sung sau đây.
Lớp học lập trình
Mã mẫu