听说Compose与RecyclerView结合会有水土不服?

背景&笔者碎碎谈

最近Compose也渐渐火起来了,作为google力推的ui结构,咱们也要用起来才干进步呀!在最新一期的评测中LazyRo架构w等LazyXXX列表组件已经渐渐迫临RecyclerView的功能了!架构师和程序员的区别可是仍是有很多同学顾忌呀源码精灵永久兑换码!不要紧,咱们就算用原有的view开发系统,也能够快速迁移到compose,这个利器便是ComposeView了,那么咱们在RecyclerView的基础上,googleplay集成Compose用起来!这样咱们有Recycle源码编程器rView的功能又有Compose的优点不是嘛!信任很源码编辑器下载多人都有跟我相同的想法,可是这两者结合起来可是有躲藏的功能开支!(本次使用compose版别为1.1.1)

在原有view系统接入Compose

在纯compose项目中,咱们都会用setContent替代原有view系统的setC架构工程师ontent性能优化View,比方

setContent {
    ComposeTestTheme {
        // A surface container using the 'background' color from the theme
        Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
            Greeting("Android")
            Hello()
        }
    }
}

那么setContent究竟做了什么事情呢?咱们看下页面性能优化源码

public fun ComponentActivity.setContent(
    parent: CompositionContext? = null,
    content: @Composable () -> Unit
) {
    val existingComposeView = window.decorView
        .findViewById<ViewGroup>(android.R.id.content)
        .getChildAt(0) as? ComposeView
    if (existingComposeView != null) with(existingComposeView) {
        setParentCompositionContext(parent)
        setContent(content)
    } else ComposeView(this).apply {
        // 第一步走到这儿
        // Set content and parent **before** setContentView
        // to have ComposeView create the composition on attach
        setParentCompositionContext(parent)
        setContent(content)
        // Set the view tree owners before setting the content view so that the inflation process
        // and attach listeners will see them already present
        setOwners()
        setContentView(this, DefaultActivityContentLayoutParams)
    }
}

由于是第一次进入,那么必定就走到了else分支,其实便是创立了一个ComposgoogleeView,放在了android.R.id.content里边的第一个child中,这儿就能够看到,coGompose并不是完全脱了原有的view系统,而是采用了移花接木的方式,把架构是什么意思compose系统迁移了过来!Compo架构师seView便是咱们能用Compose的条件啦!所以在原有的view系统手机性能优化中,咱们也能够经过ComposeView去“嫁接”到view系统中,咱们举个比如

class CustomActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_custom)
        val recyclerView = this.findViewById<RecyclerView>(R.id.recyclerView)
        recyclerView.adapter = MyRecyclerViewAdapter()
        recyclerView.layoutManager = LinearLayoutManager(this)
    }
}

class MyRecyclerViewAdapter:RecyclerView.Adapter<MyComposeViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyComposeViewHolder {
        val view = ComposeView(parent.context)
        return MyComposeViewHolder(view)
    }
    override fun onBindViewHolder(holder: MyComposeViewHolder, position: Int) {
          holder.composeView.setContent {
              Text(text = "test $position", modifier = Modifier.size(200.dp).padding(20.dp), textAlign = TextAlign.Center)
          }
    }
    override fun getItemCount(): Int {
        return 200
    }
}
class MyComposeViewHolder(val composeView:ComposeView):RecyclerView.ViewHolder(composeView){
}

工资超过5000怎么扣税样一来,咱们的compose就被移到了RecyclerView中,当然,每一列其实便是一个架构师证书文本。嗯!普普通通,如同也没架构是什么意思啥特别的对吧,假设这个时分你打开了profiler,当咱公积金们向下滑动的时分,会发现内存会渐渐的往上浮动

传闻Compose与RecyclerView结合会有不服水土?
滑动嘛!有点内存很正常,究竟谁不生成对象呢,可是这跟咱们平常用RecyclerView的时分有点差异,由于RecyclerView滑动的涨幅可没有这个大,那究竟是什么原因导架构图模板致的呢?

探究Compose

有过对Compose了解的同学可能会知道,CompoGooglese的界面构成会有一个重源码1688组的过程,当然!本文就不展开聊重组了,由于这类文章有挺多的(填个坑,假如有机会就填),咱们聊点特别的,那么什么时分停止重组呢?或许说什么时分这个Compose被dispose掉,即不再参加重组!

Dispos枸杞e战略

其实咱们的ComposeView,以1.1龚俊.1版别为例,其实创立的时分,也创立了取消重组战略,即

@Suppress("LeakingThis")
private var disposeViewCompositionStrategy: (() -> Unit)? =
    ViewCompositionStrategy.DisposeOnDetachedFromWindow.installFor(this)

这个战略是什么呢?咱们google网站登录入口点进去看源码

object DisposeOnDetachedFromWindow : ViewCompositionStrategy {
    override fun installFor(view: AbstractComposeView): () -> Unit {
        val listener = object : View.OnAttachStateChangeListener {
            override fun onViewAttachedToWindow(v: View) {}
            override fun onViewDetachedFromWindow(v: View?) {
                view.disposeComposition()
            }
        }
        view.addOnAttachStateChangeListener(listener)
        return { view.removeOnAttachStateChangeListener(listener) }
    }
}

看起来是不是很简单呢,其实就工龄越长退休金越多吗加了一个工龄越长退休金越多吗监听,在onViewDeta前端性能优化chedFromWindow的时分调用的view.disposeComposition(),声明当时的ComposeView不参加接下来的重组过程了,咱们再继续看

fun disposeComposition() {
    composition?.dispose()
    composition = null
    requestLayout()
}

再看dispose办法

override fun dispose() {
    synchronized(lock) {
        if (!disposed) {
            disposed = true
            composable = {}
            val nonEmptySlotTable = slotTable.groupsSize > 0
            if (nonEmptySlotTable || abandonSet.isNotEmpty()) {
                val manager = RememberEventDispatcher(abandonSet)
                if (nonEmptySlotTable) {
                    slotTable.write { writer ->
                        writer.removeCurrentGroup(manager)
                    }
                    applier.clear()
                    manager.dispatchRememberObservers()
                }
                manager.dispatchAbandons()
            }
            composer.dispose()
        }
    }
    parent.unregisterComposition(this)
}

那么怎么样才算是不参加接下里的重组呢,其实便是这儿

slotTable.write { writer ->
    writer.removeCurrentGroup(manager)
}
...
composer.dispose()

而removeCurrentGroup其实便是把当时的group移除了

for (slot in groupSlots()) {
    when (slot) {
        .... 
        is RecomposeScopeImpl -> {
            val composition = slot.composition
            if (composition != null) {
                composition.pendingInvalidScopes = true
                slot.composition = null
            }
        }
    }
}

这儿架构师工资又多了一个概念,slottable,咱们能够这么了解,这架构师儿边便是Compose的快照系统,其实就相当于对应着某个时间view的状况!之所以Compose是声明式的,便是经过slottable里的slogoogle中国t去判别,假如最新的slot跟前一个slot不一架构师证书致,就回调给监听者,完成更新!这儿又是一个大论题了,咱们点到js性能优化为止

传闻Compose与RecyclerView结合会有不服水土?

跟RecyclerView有抵触吗

咱们看到,默认的战略是当view被移出当时的wgoogle服务框架indow就不参加重组了,嗯!这个在99%的场景都是有用的战略,由于你都看不到了,还重组干嘛对吧!可是这跟工商银行咱们的RecyclerView有什么抵触吗?想想看!诶,RecyclerView最重要的是啥,Recycle呀,便是由于会重复使用holderGo,直接重复使用了googleview才显得google服务框架高效不是嘛!那么问题就来了

传闻Compose与RecyclerView结合会有不服水土?
如图,咱们item5其电脑性能优化实完全能够使用item1进行显示的对不对,差公司让员工下班发手机电量截图别就仅仅Text组件的文本不一致算了,可是咱们从上文的分析来看,这个ComposeView对应的composition被回收架构图模板了,即不参加重组了,换句话来说,咱们Adapter在onBindViewHolder的时分,岂不是用了一个没有compositon的ComposeView(即不能参加重组的ComposeView)?这样怎么行呢?咱们来猜一下源码中的图片,那么这样的话,RecyclerView岂不是都要生成新的C架构图模板ompos龚俊eView(即每次都调用onCreateViewHolder)才干确保公司让员工下班发手机电量截图正确?emmm,很有道理,可是却不是的!假如咱们把代码跑起来看的话,复用的时分依旧是会调用o架构师nBindViewHolder,这便是Compos公司让员工下班发手机电量截图e的隐秘了,那js性能优化么这个隐秘架构图怎么制作在哪呢

override fun onBindViewHolder(holder: MyComposeViewHolder, position: Int) {
      holder.composeView.setContent {
          Text(text = "test $position", modifier = Modifier.size(200.dp).padding(20.dp), textAlign = TextAlign.Center)
      }
}

其实便是在Comp页面性能优化o前端性能优化seView的setContent办法中,

fun setContent(content: @Composable () -> Unit) {
    shouldCreateCompositionOnAttachedToWindow = true
    this.content.value = content
    if (isAttachedToWindow) {
        createComposition()
    }
}
fun createComposition() {
    check(parentContext != null || isAttachedToWindow) {
        "createComposition requires either a parent reference or the View to be attached" +
            "to a window. Attach the View or call setParentCompositionReference."
    }
    ensureCompositionCreated()
}

终究调用的是

private fun ensureCompositionCreated() {
    if (composition == null) {
        try {
            creatingComposition = true
            composition = setContent(resolveParentCompositionContext()) {
                Content()
            }
        } finally {
            creatingComposition = false
        }
    }
}

看到了吗!假如composition为null,就Google会从头创立一个!这样ComposeView就完全嫁接到RecyclerView中而不出现问题了!

其他Dispose战略

咱们看到,电脑性能优化虽然在ComposeView在Recyc架构师工资lerVie工龄差一年工资差多少w中能正常运行,可是还存在缺点对不对,由于每源码网站次复google谷歌搜索主页用都要从头创立一个composition对象是不是!归根究竟便是,咱们默认的dispose战略不太合适这种拥有复用逻辑或许自己生命周期的组件使用,那么有其他战略合适RecyclerView吗?别急,其实是有的,比方DisposeOnViewTreeLifecycleDestr架构图oyed

object DisposeOnViewTreeLifecycleDestroyed : ViewCompositionStrategy {
    override fun installFor(view: AbstractComposeView): () -> Unit {
        if (view.isAttachedToWindow) {
            val lco = checkNotNull(ViewTreeLifecycleOwner.get(view)) {
                "View tree for $view has no ViewTreeLifecycleOwner"
            }
            return installForLifecycle(view, lco.lifecycle)
        } else {
            // We change this reference after we successfully attach
            var disposer: () -> Unit
            val listener = object : View.OnAttachStateChangeListener {
                override fun onViewAttachedToWindow(v: View?) {
                    val lco = checkNotNull(ViewTreeLifecycleOwner.get(view)) {
                        "View tree for $view has no ViewTreeLifecycleOwner"
                    }
                    disposer = installForLifecycle(view, lco.lifecycle)
                    // Ensure this runs only once
                    view.removeOnAttachStateChangeListener(this)
                }
                override fun onViewDetachedFromWindow(v: View?) {}
            }
            view.addOnAttachStateChangeListener(listener)
            disposer = { view.removeOnAttachStateChangeListener(listener) }
            return { disposer() }
        }
    }
}

然后咱们在ViewHolder的init办法中对composeview设置一下就能够了

class MyComposeViewHolder(val composeView:ComposeView):RecyclerView.ViewHolder(composeView){
    init {
        composeView.setViewCompositionStrategy(
            ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
        )
    }
}

为什么DisposeOnViewTreeLifecycleDestroyed更加合适呢?咱们能够看到在onViewAttachedToWindow中调用了 installForLi工商银行fecycle(view, lco.lifecycle) 办法,然后就工龄越长退休金越多吗removeOnAttachStateChangeLi工龄差一年工资差多少stener,确保了该ComposeView创立的时分只会被调用一次,那么removeOnAttachStateChangeListener又做了什么呢?

val observer = LifecycleEventObserver { _, event ->
    if (event == Lifecycle.Event.ON_DESTROY) {
        view.disposeComposition()
    }
}
lifecycle.addObserver(observer)
return { lifecycle.removeObserver(observer) }

能够看到,是在对应的生命周期事件为ON_DESTROY(Lifecycle.源码编辑器Event跟activity生命周期不是一一对应的,要留意)的时分,才调用view.disp架构图模板os架构是什么意思eComposition(),本比如的lifec电脑性能优化ycleOwner便是CustomActivity啦,这样就架构工程师确保了只要当时被lifecycleOwner处于特定状况的时分,才会源码中的图片毁掉,这样是不是就提高了compose的功能工龄差一年工资差多少了!

扩展

咱们留心到了Comp性能优化ose其实存在这样的小问题,那么假如咱们用了其他的组件相似RecyclerView这种的怎么办,又或许咱们的开发没有读过这篇文章怎么办!(ps:看到这儿的同学还不点赞点赞),不源码编辑器下载要紧,官方也留意到了,并且在1.3.0-alpha02以上版别添加了更换了默认战略,咱们google商店来看一下

val Default: ViewCompositionStrategy
    get() = DisposeOnDetachedFromWindowOrReleasedFromPool
object DisposeOnDetachedFromWindowOrReleasedFromPool : ViewCompositionStrategy {
    override fun installFor(view: AbstractComposeView): () -> Unit {
        val listener = object : View.OnAttachStateChangeListener {
            override fun onViewAttachedToWindow(v: View) {}
            override fun onViewDetachedFromWindow(v: View) {
            // 留意这儿
                if (!view.isWithinPoolingContainer) {
                    view.disposeComposition()
                }
            }
        }
        view.addOnAttachStateChangeListener(listener)
        val poolingContainerListener = PoolingContainerListener { view.disposeComposition() }
        view.addPoolingContainerListener(poolingContainerListener)
        return {
            view.removeOnAttachStateChangeListener(listener)
            view.removePoolingContainerListener(poolingContainerListener)
        }
    }
}

D源码网站ispogoogle商店s架构图eOnDetachedFromWindow从变成了DisposeOnDetachedFromWindowOrReleasedFromPool,其实首要改变点便是一个vie架构图怎么画w.isWithinPoolingContainer = false,才会进行dispose,isWithinPoolingContainer界说如下

传闻Compose与RecyclerView结合会有不服水土?

也便是说,假如咱们view的先人存在isPoolingContainer = trgoogleplay安卓版下载ue的时分,就不会进行dispose啦!所以说,假如咱们的自界说view是这种状况,就必定要把isPoolingContainer变成true才不会有躲藏的功能开支噢!当然,RecyclerView也要同步到1.google3.0-aljs性能优化p源码编辑器ha02以上才会有这个属性改写!现在安稳版别仍工龄越长退休金越多吗是会存在本文的躲藏功能开支,请留意噢!不过信任看完这篇文章,功能优化啥的,不存在了对不对!

结语

Compose是个大论题,期望开发者都能够用上并深化下去,由于声明式ui会越来越盛行,Compose相对于传统view系统也有大源码1688幅度的功能提升与架构提升!最终记得点赞关注呀!往期也很精彩!

我正在参加页面性能优化技术社区创作者签约方案招募活动,点击链接报名投稿。

发表评论

提供最优质的资源集合

立即查看 了解详情