Content Pooling
When a Primitive Component is being mounted, its content (View or Drawable) needs to be either initialized or reused from the recycling pool. If the pool is empty, a new instance will be created at that time, which might keep the UI thread too busy and drop one or more frames. To mitigate that, the Litho framework can pre-allocate a few instances and put them in the recycling pool to improve performance.
Content pooling is especially recommended for Primitive Components that inflate a complex View, which is time-consuming to create from scratch.
Configuring poolsβ
In order to configure content pools, the properties of the View/Drawable Allocator can also be customized.
The ViewAllocator
and DrawableAllocator
have properties that allow for configuring the pool behaviour:
canPreallocate
- enables pre-allocation for this Primitive Component (disabled by default)poolSize
- defines the number of instances for the Litho framework to pre-allocate (default value is three); settingpoolSize
to 0 disables pooling of a given View/Drawable
Primitive Components with canPreallocate
set to true
will be pre-allocated by Litho framework automatically before the component is mounted.
If creating new instances of the content is time-consuming but not very memory-consuming, it's recommended to keep the pool size high.
If there are memory concerns (especially for memory-consuming content), smaller pool sizes are recommended.
Pre-allocation exampleβ
In order for mount content to be pre-allocated, at least the canPreallocate
property should be set to true
. Use poolSize
to configure the amount of items in the pool, as shown in the example below:
ViewAllocator(canPreallocate = true, poolSize = 10) { context -> EditText(context) }
For the SampleTextInput component example above, ten instances of EditText will be created and pre-allocated in the recycling pool.
Pre-filling content poolβ
If automatic pre-allocation isn't enough, Litho provides an API that allows for manually pre-filling content pool ahead of time. For example, it may be useful when there is a complex component that needs to be displayed on the next screen. Pre-filling such component before the user opens the next screen may improve performance. In order to manually pre-fill content pool, you should use MountContentPools.prefillMountContentPool method, as shown in the example below:
// preallocate 40 TestTextViewPrimitiveComponent components
MountContentPools.prefillMountContentPool(androidContext, 40, TestTextViewPrimitiveComponent.ALLOCATOR)
The last parameter of prefillMountContentPool
is the ContentAllocator
, which for convenience, can be stored inside of PrimitiveComponent's companion object:
class TestTextViewPrimitiveComponent(val style: Style? = null) : PrimitiveComponent() {
override fun PrimitiveComponentScope.render(): LithoPrimitive {
return LithoPrimitive(
layoutBehavior = FixedSizeLayoutBehavior(100.px, 100.px),
mountBehavior = MountBehavior(ALLOCATOR) {},
style = style)
}
companion object {
val ALLOCATOR = ViewAllocator(poolSize = 10) { context -> TextView(context) }
}
}
In order for content pre-filling to work properly, it's important to pass the same instance of an Allocator to the Primitive's MountBehavior
and to prefillMountContentPool
method.