CameraX: Getting Started
Learn how to implement camera features on Android using CameraX library By Tino Balint.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
CameraX: Getting Started
25 mins
- What Is CameraX?
- Getting Started
- Pre-Built Kotlin Classes and Dependencies
- Familiarizing Yourself With the App Screen
- Creating a Camera Preview
- Creating Use Cases: createPreviewUseCase
- Creating Use Cases: updateTransform
- Creating Use Cases: createCaptureUseCase
- Requesting Permission to Use the Camera
- Toggling the Camera Lens
- Capturing Images
- Storing Images to Memory
- Adding Click Listeners
- Storing Images to File
- Adding Vendor Extensions
- Listening for the Image Extension
- Where to Go From Here?
Adding Click Listeners
Next, you’ll add a click listener so that you can click on the preview and take a picture. Go back to onCreate
and replace setClickListeners
with this:
private fun setClickListeners() {
toggleCameraLens.setOnClickListener { toggleFrontBackCamera() }
previewView.setOnClickListener { takePicture() }
}
Build and run. Click on the preview now to take a picture. Sweet!
Once you take a picture, you can compare it with the live preview, like this picture of a picture. :]
Storing Images to File
Congratulations, your app can take pictures! But what if you want to save them?
You can do that with this updated version of savePictureToFile
. Replace the currently empty method with this:
private fun savePictureToFile() {
// 1
fileUtils.createDirectoryIfNotExist()
val file = fileUtils.createFile()
// 2
imageCapture?.takePicture(file, getMetadata(), executor,
object : ImageCapture.OnImageSavedListener {
override fun onImageSaved(file: File) {
// 3
runOnUiThread {
takenImage.setImageURI(FileProvider.getUriForFile(this@PhotoActivity,
packageName,
file))
enableActions()
}
}
override fun onError(imageCaptureError: ImageCapture.ImageCaptureError,
message: String,
cause: Throwable?) {
// 4
Toast.makeText(this@PhotoActivity,
getString(R.string.image_capture_failed),
Toast.LENGTH_SHORT).show()
}
})
}
Here’s what you are doing in savePictureToFile
:
- Create a destination directory and file using the helper methods in the Pictures/Photo_session directory on your device.
- Call
takePicture
with three parameters: The newly-created file to save the image, the metadata for the image and an executor to define which thread to call these methods on. Metadata stores the geographical location of the photo. It also indicates whether the system needs to render the image mirrored horizontally or vertically. For instance,isReversedHorizontal
will be true for a selfie. - After taking the photo, if there are no errors, you set the image to
ImageView
and enable user actions. Notice that you set the image using URI instead of the bitmap. You do this because you have a file object. - If there are any errors, you show them to the user as a
Toast
.
Build and run to test this new feature. Set the Save Image switch to save.
Take a photo. Now look in the Images/Photo_session directory on your device. Notice something? The image looks very different than the one in your app. That’s because you’re seeing it full-screen. You don’t want people leaving your app to do this so you’ll add this feature now.
Replace setClickListeners
with the following:
private fun setClickListeners() {
toggleCameraLens.setOnClickListener { toggleFrontBackCamera() }
previewView.setOnClickListener { takePicture() }
takenImage.setOnLongClickListener {
showImagePopup()
return@setOnLongClickListener true
}
}
In this new version of setClickListeners
, you add another listener that runs showImagePopup
when the user long-clicks on the most recent photo. saveImagePopup
is already in the starter project.
Build and run. Take a picture and then long-click on it. It’s full-screen now in its normal aspect ratio and size. Click anywhere again and you’ll return to split-view.
Take a moment to appreciate what you’ve created here!
Adding Vendor Extensions
There’s one more feature you want to add to your camera app: What if your users want to add special effects to their photos like Night Mode or Bokeh?
No problem. With CameraX, you can add these features with only a few lines of code.
- Huawei (HDR, Portrait): Mate 20 series, P30 series, Honor Magic 2, Honor View 20.
- Samsung (HDR, Night, Beauty, Auto): Galaxy Note 10 series.
- Huawei (HDR, Portrait): Mate 20 series, P30 series, Honor Magic 2, Honor View 20.
- Samsung (HDR, Night, Beauty, Auto): Galaxy Note 10 series.
Add this code below savePictureToMemory
:
private fun enableExtensionFeature(
imageCaptureExtender: ImageCaptureExtender
) {
if (imageCaptureExtender.isExtensionAvailable) {
imageCaptureExtender.enableExtension()
} else {
Toast.makeText(this, getString(R.string.extension_unavailable),
Toast.LENGTH_SHORT).show()
extensionFeatures.setSelection(0)
}
}
In this method, you’re enabling an extension, if it’s available. Otherwise, you notify the user that it isn’t available and remove the option from the drop-down menu.
enableExtensionFeature
needs to know the image capture extender you want to use. You’ll provide that with the method below:
private fun applyExtensions(
builder: ImageCaptureConfig.Builder
) {
when (ExtensionFeature.fromPosition(extensionFeatures.selectedItemPosition)) {
ExtensionFeature.BOKEH ->
enableExtensionFeature(BokehImageCaptureExtender.create(builder))
ExtensionFeature.HDR ->
enableExtensionFeature(HdrImageCaptureExtender.create(builder))
ExtensionFeature.NIGHT_MODE ->
enableExtensionFeature(NightImageCaptureExtender.create(builder))
else -> {
}
}
}
And add these to your import statements above:
import androidx.camera.extensions.HdrImageCaptureExtender
import androidx.camera.extensions.BokehImageCaptureExtender
import androidx.camera.extensions.NightImageCaptureExtender
In the method above, you check the currently-selected item from the drop-down menu and then create an image extender based on that option.
Listening for the Image Extension
Now that you’ve created this array of image extenders, you’ll add a listener for the drop-down menu.
Go back to onCreate
and replace setClickListeners
with this:
private fun setClickListeners() {
toggleCameraLens.setOnClickListener { toggleFrontBackCamera() }
previewView.setOnClickListener { takePicture() }
takenImage.setOnLongClickListener {
showImagePopup()
return@setOnLongClickListener true
}
extensionFeatures.onItemSelectedListener =
object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parentView: AdapterView<*>,
selectedItemView: View,
position: Int,
id: Long
) {
if (ExtensionFeature.fromPosition(position) != ExtensionFeature.NONE) {
previewView.post { startCamera() }
}
}
override fun onNothingSelected(parentView: AdapterView<*>) {}
}
}
Now, when the user selects an available extension, you’ll start the camera — which will automatically apply the extensions.
The only thing left is to call applyExtensions
from within createCaptureUseCase
. Add the call right before the return:
private fun createCaptureUseCase(): ImageCapture {
val imageCaptureConfig = ImageCaptureConfig.Builder()
.apply {
setLensFacing(lensFacing)
setTargetRotation(previewView.display.rotation)
setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
}
applyExtensions(imageCaptureConfig)
return ImageCapture(imageCaptureConfig.build())
}
Build and run. The extensions are now available from the drop-down menu on any of the supported devices. Note that the app only applies the extensions to the most recent photo.
Where to Go From Here?
Download the final project using the Download Materials button at the top or the bottom of the tutorial.
In this tutorial, you learned how to use CameraX to preview, take and store photos. You also saw how this library simplifies the process of adding options for special effects.
If you want to learn more, check out the official CameraX documentation.
I hope you enjoyed this tutorial! If you have any questions or comments, please join the forum discussion below.