Skip to content

Commit

Permalink
Integrate custom scoped pooling with ComposeComponent
Browse files Browse the repository at this point in the history
Summary: As per title - in this diff we're making `ComposeComponent` to use custom scoped pooling. It'll dispose composition when the `ComposeView` is discarded from the pool.

Reviewed By: kingsleyadio

Differential Revision: D64236148

fbshipit-source-id: 680fa599f0082147eb9d82903bb5b7a724e500dd
  • Loading branch information
zielinskimz authored and facebook-github-bot committed Oct 18, 2024
1 parent 1cff5e2 commit de88eca
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 4 deletions.
2 changes: 2 additions & 0 deletions litho-compose/src/main/kotlin/com/facebook/litho/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ load(
"LITHO_COMPOSE_UI_TARGET",
"LITHO_JAVA_TARGET",
"LITHO_KOTLIN_STDLIB_TARGET",
"LITHO_RES_TARGET",
"litho_android_library",
"make_dep_path",
)
Expand All @@ -44,6 +45,7 @@ litho_android_library(
"//fbandroid/libraries/components/litho-widget/src/main/java/com/facebook/litho/widget:widget-bare",
"//fbandroid/libraries/compose/view:view",
LITHO_KOTLIN_STDLIB_TARGET,
LITHO_RES_TARGET,
LITHO_COMPOSE_FOUNDATION_TARGET,
LITHO_COMPOSE_RUNTIME_TARGET,
LITHO_COMPOSE_UI_TARGET,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ class ComposeComponent(
CompositionContextHelper.bind(
content, requireNotNull(androidContext.findComponentActivity()))
onUnbind {
content.disposeComposition()
CompositionContextHelper.unbind(content, usedCustomCompositionContext)
}
}
Expand All @@ -70,9 +69,17 @@ class ComposeComponent(

companion object {
@JvmField
val ALLOCATOR: ViewAllocator<MetaComposeView> = ViewAllocator { context ->
MetaComposeView(context)
}
val ALLOCATOR: ViewAllocator<MetaComposeView> =
ViewAllocator(
useCustomPoolScope = true, onDiscarded = { content -> content.disposeComposition() }) {
context ->
MetaComposeView(context).apply {
// Normally content shouldn't be modified within ViewAllocator, but in this case
// we want all MetaComposeViews used by ComposeComponent to use
// ComposeComponentViewCompositionStrategy
setViewCompositionStrategy(ComposeComponentViewCompositionStrategy)
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.facebook.litho

import android.view.View
import androidx.compose.ui.platform.ViewCompositionStrategy.DisposeOnDetachedFromWindow
import androidx.core.view.ancestors
import com.facebook.compose.view.AbstractMetaComposeView
import com.facebook.compose.view.MetaViewCompositionStrategy

/**
* The composition will be disposed automatically when the view is detached from a window, unless it
* is pooled by Litho.
*
* When not pooled by Litho, this behaves exactly the same as [DisposeOnDetachedFromWindow].
*/
object ComposeComponentViewCompositionStrategy : MetaViewCompositionStrategy {
override fun installFor(view: AbstractMetaComposeView): () -> Unit {
val listener =
object : View.OnAttachStateChangeListener {
override fun onViewAttachedToWindow(v: View) = Unit

override fun onViewDetachedFromWindow(v: View) {
if (!view.isWithinLithoPoolingContainer) {
view.disposeComposition()
}
}
}
view.addOnAttachStateChangeListener(listener)

return { view.removeOnAttachStateChangeListener(listener) }
}
}

/** Whether one of this View's ancestors has R.id.litho_pooling_container tag set to true. */
val View.isWithinLithoPoolingContainer: Boolean
get() {
ancestors.forEach {
if (it is View && it.getTag(R.id.litho_pooling_container) == true) {
return true
}
}
return false
}
1 change: 1 addition & 0 deletions litho-core/src/main/res/values/ids.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@
<item type="id" name="component_touch_listener"/>
<item type="id" name="component_node_info"/>
<item type="id" name="component_focus_order"/>
<item type="id" name="litho_pooling_container"/>

</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import android.view.MotionEvent;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.facebook.litho.R;
import java.util.ArrayList;
import java.util.List;

Expand All @@ -48,6 +49,7 @@ public LithoRecyclerView(Context context, @Nullable AttributeSet attrs) {

public LithoRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setTag(R.id.litho_pooling_container, true);
}

/**
Expand Down

0 comments on commit de88eca

Please sign in to comment.