[AUDIO LOGO]
DONOVAN MCMURRAY: Hi, Donovan here.
And in this video, we're going to look
at CameraX's CameraProvider interface and the class that
implements it--
ProcessCameraProvider.
This video assumes you're already
familiar with CameraX use cases.
So if you aren't, or if you need a refresher,
please check out our CameraX concepts video
linked in the description.
We'll finish the app we started in the CameraX setup
and permissions video.
So make sure you've watched that one as well.
In CameraX, a CameraProvider is an easy way
to add camera functionality to your app
while still giving you flexibility
over certain implementation details like enabling output
image rotation or setting the output image
format in ImageAnalysis.
Additionally, with a CameraProvider,
you can choose to use CameraX's preview view
or you can use a custom surface for your preview, which
can come in handy if you use that surface
in other parts of your app.
In this video, we'll use preview view
because it makes things so much easier,
but I'll point out where you could
plug in your custom surface.
Now let's take a look where we left off in our camera app.
As a reminder, we're building an app that shows a preview
and allows the user to take a picture.
First, make sure that our top-level reference
to image capture is uncommented from the last video.
Next, we'll implement the startCamera method,
which will set up the use cases and associate them
with our activity's lifecycle.
In this method, we're going to use a Kotlin
coroutine to handle an asynchronous callback,
so we need to make it a suspend function.
This video doesn't explain Kotlin coroutines,
suspend functions, and coroutine scopes.
So if you need more information, follow the Kotlin coroutines
in Android link in the video description.
Then, where we invoke the startCamera method,
we need to wrap it in a coroutine scope like this.
Now, we can implement the startCamera method.
Start by getting an instance of a ProcessCameraProvider,
which implements the CameraProvider interface.
The getInstance method returns a listenable future
which will contain the ProcessCameraProvider instance.
Thanks to the concurrent Jetpack API
we included in our dependencies, we
can wait for this listenable future result
with the await function.
Once we have the CameraProvider, we
can proceed with our camera setup.
First, we need to build the use cases our app needs,
starting with the preview.
We also need to call setSurfaceProvider,
passing the surface provider on the preview view
that we added to our view layout.
This is where you can pass in a custom service provider
if you need to.
Then we need to build the ImageCapture use case like so.
Also set the camera selector to pick the default front
camera for a great selfie shot.
Now, create a try block where we will bind the use
cases to the CameraProvider.
First, it's a good idea to call unbindAll to remove
any previously bound use cases.
Then call bindToLifecycle on the CameraProvider,
passing in this activity as the lifecycle owner,
our cameraSelector, and the preview and ImageCapture use
cases.
Note that this function returns a camera object which
can be used to perform operations like zoom,
flash, and focus, but we won't be implementing
any of that in this video.
Let's run this app on our trusty test device
to see it in action.
The first thing we see is the permission
prompt to get access to the camera.
I'll select "while using the app" so that the next time we
open the app, the permissions will already be granted.
And as you can see, the front camera is activated,
and the preview is being shown.
You'll also see the Take Photo button,
but nothing happens when we click it.
That's because we haven't set it up yet, so let's do that now.
In the onCreate method, get the ImageCapture button and call
setOnClickListener on it, invoking the takePhoto function
in the callback.
Now, we need to define the takePhoto function.
When the user wants to take a photo,
first define a name to use for the photo file.
Then set up content values which will
contain the file configuration for MediaStore
to save the photo.
Next, use CameraX's ImageCapture.OutputFileOptions
builder, passing in the content resolver for main activities
context, MediaStore's external content
location, and the MediaStore configuration we set up
in content values.
Then call takePicture on the ImageCapture use case
to have CameraX handle the image capture, passing in the output
options, an executor in which the callback methods will
be run, and an onImageSaved callback object for handling
the error and success states.
Let's run the app again to see this new functionality.
Now, when we click the Take Photo button,
we see a Toast message that the photo was successfully saved.
And if we switch over to our Photos app,
we see the photo there as well.
Not bad, if I do say so myself.
Congratulations.
You now know how to create a simple camera app
using CameraX's CameraProvider.
We have a lot of resources that go further
with the concepts we've covered in this video series,
so check those out in the video description.
Happy coding.