Start by downloading and installing the latest version of Android Studio on your host machine.
The instructions for this learning path were tested on a host machine running macOS, but you can use any of the supported hardware systems listed on the Install Android Studio webpage on the Android Developer website.
After installation, open Android Studio and do the following:
Before you start coding, here are some useful tips:
To navigate to a file, simply press the Shift key twice, input the file name, select the correct result using the up and down arrow keys, and then press Enter.
Every time after you copy-and-paste a code block from this Learning Path, ensure that you import the correct classes and resolve any errors. For more information, see the Auto import web page.
Navigate to File > New > New Project.
Select Empty Views Activity in the Phone and Tablet gallery as Figure 1 shows, then select Next.
Choose a project name, and select the default configurations as Figure 2 shows.
Make sure that the Language field is set to Kotlin, and the Build configuration language field is set to Kotlin DSL.
CameraX is a Jetpack library, built to help make camera app development easier. It provides a consistent, easy-to-use API that works across the vast majority of Android devices with great backward-compatibility.
Wait for Android Studio to sync project with Gradle files. This might take several minutes.
Once the project is synced, navigate to libs.versions.toml
in your project’s root directory. See Figure 3. This file serves as the version catalog for all dependencies that the project uses.
For more information on version catalogs, see Migrate your build to version catalogs .
[versions]
section. This defines the version of CameraX libraries that you will be using.
camerax = "1.4.0"
[libraries]
section. This declares the group, name and version of CameraX dependencies.
camera-core = { group = "androidx.camera", name = "camera-core", version.ref = "camerax" }
camera-camera2 = { group = "androidx.camera", name = "camera-camera2", version.ref = "camerax" }
camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "camerax" }
camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "camerax" }
build.gradle.kts
in your project’s app
directory, then insert the following lines into dependencies
block. This introduces the dependencies listed above into the app
subproject:
implementation(libs.camera.core)
implementation(libs.camera.camera2)
implementation(libs.camera.lifecycle)
implementation(libs.camera.view)
build.gradle.kts
file, append the following lines to the end of android
block to enable the view binding feature:
buildFeatures {
viewBinding = true
}
You can also click the Sync Project with Gradle Files button in the toolbar, or enter the corresponding shortcut to start a sync.
Navigate to the MainActivity.kt
source file and make the changes that Figure 5 shows in the View Binding screenshot.
This inflates the layout file into a view binding object, and stores it in a member variable within the view controller for easier access later.
activity_main.xml
, replace the placeholder “Hello World!” in TextView
with a camera preview view:
<androidx.camera.view.PreviewView
android:id="@+id/view_finder"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:scaleType="fillStart" />
MainActivity.kt
to store camera-related objects:
// Camera
private var camera: Camera? = null
private var cameraProvider: ProcessCameraProvider? = null
private var preview: Preview? = null
setupCamera()
and bindCameraUseCases()
within MainActivity.kt
:
private fun setupCamera() {
viewBinding.viewFinder.post {
cameraProvider?.unbindAll()
ProcessCameraProvider.getInstance(baseContext).let {
it.addListener(
{
cameraProvider = it.get()
bindCameraUseCases()
},
Dispatchers.Main.asExecutor()
)
}
}
}
private fun bindCameraUseCases() {
// TODO: TO BE IMPLEMENTED
}
bindCameraUseCases()
method:
private fun bindCameraUseCases() {
val cameraProvider = cameraProvider
?: throw IllegalStateException("Camera initialization failed.")
val cameraSelector =
CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_FRONT).build()
// Only using the 4:3 ratio because this is the closest to MediaPipe models
val resolutionSelector =
ResolutionSelector.Builder()
.setAspectRatioStrategy(AspectRatioStrategy.RATIO_4_3_FALLBACK_AUTO_STRATEGY)
.build()
val targetRotation = viewBinding.viewFinder.display.rotation
// Preview usecase.
preview = Preview.Builder()
.setResolutionSelector(resolutionSelector)
.setTargetRotation(targetRotation)
.build()
// Must unbind the use-cases before rebinding them
cameraProvider.unbindAll()
try {
// A variable number of use-cases can be passed here -
// camera provides access to CameraControl & CameraInfo
camera = cameraProvider.bindToLifecycle(
this, cameraSelector, preview,
)
// Attach the viewfinder's surface provider to preview use case
preview?.surfaceProvider = viewBinding.viewFinder.surfaceProvider
} catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
}
MainActivity.kt
, and declare a TAG
constant value for Log
calls to work correctly. This companion object is useful in enabling you to define all the constants and shared values accessible across the entire class.
companion object {
private const val TAG = "MainActivity"
}
In the next section, you will build and run the app to ensure that the camera works as expected.