Implementations
We provide a few Recorder
implementations that you can choose from depending on your case.
Using them is a bit different but they all share the same functionality from the Recorder
interface.
- A default implementation called
DefaultRecorder
- A few UI-specific implementations. These can be found in the
io.video:videokit-recorder-ui
module and generally implementRecorder
by delegation to someDefaultRecorder
under the hood.
The default recorder
DefaultRecorder
is the low level implementation that, unlike the others, is detached from
the UI. You will typically hold the default instance in the "view model" layer of your app, but you are free to do otherwise.
The recorder offers many constructors that should fit your use case:
DefaultRecorder(Context, SavedStateHandle?)
: to be used from AAC ViewModels, which can receive aSavedStateHandle
into their constructor.DefaultRecorder(ComponentActivity)
: to be used from activities.DefaultRecorder(Fragment)
: to be used from fragments.DefaultRecorder(Context, LifecycleOwner?, SavedStateRegistry, ActivityResultCaller)
: lower level constructor.
For example, in the view model scenario:
class RecordViewModel(app: Application, state: SavedStateHandle) : AndroidViewModel(app) {
val recorder = DefaultRecorder(app, state)
override fun onCleared() {
super.onCleared()
recorder.destroy()
}
}
As you can see, the DefaultRecorder
must be destroyed when you're done with it.
Showing the UI
The default recorder creates and caches an android.view.View
with the content to be shown (camera and video preview). In order to show the UI in your app, make sure to add this view to some parent view in your hierarchy:
val parentView: ViewGroup = findViewById(R.id.recorder_container)
parentView.addView(recorder.view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
Enabling activity results
Our recorder needs access to an ActivityResultCaller
to support some features like permission requests and gallery imports. By default, it will try to determine an ActivityResultCaller
from the constructor parameters. But depending on the constructor used, you might have to manually pass one:
if (recorder.activityResultCaller == null) {
recorder.activityResultCaller = ...
}
Note that ActivityResultCaller
is implemented by activities and fragments, so the SDK is always able to determine it automatically for activity and fragment constructors.
videokit-recorder-ui
module: the recorder fragment
The RecorderFragment
is a fragment implemented as described above, hosting the recorder in a view model.
It is slightly easier to use since there is no need to release or care about the UI.
You can customize the fragment after it is attached or when creating it, thanks to
the RecorderFragment.Options
class:
val options = RecorderFragment.Options.build {
overlay(R.layout.custom_controls)
direction(CameraDirection.Front)
flash(CameraFlash.Off)
uploadParams(UploadParams(title = "Video Title"))
saveToGallery(true)
maxDuration(30000L)
}
val recorder = RecorderFragment.newInstance(options)
videokit-recorder-ui
module: the recorder view
The RecorderView
is a view that holds a default recorder, to be used for codebases that do not use
fragments at all. Like the fragment, this is a very simple option, although it has the drawback that the recorder state will not be kept across activity restoration.
videokit-recorder-ui
module: Jetpack Compose recorder
For Jetpack Compose users, we provide two useful functions.
First, rememberRecorder
: use this to efficiently create a DefaultRecorder
and scope it to the composition.
Under the hood, we take care about state restoration and lifecycle management.
Lastly, a Recorder()
composable which accepts the recorder from above:
@Composable
fun RecorderScreen(modifier: Modifier = Modifier) {
val recorder = rememberRecorder()
Box(modifier) {
Recorder(recorder, Modifier.fillMaxSize())
// Overlays here...
}
}
Note that, despite the reactive composable, management of the recorder APIs must be done through the
imperative APIs of DefaultRecorder
. In fact, the default recorder is better hosted somewhere in the
view model layer for ease of access and management.