Modifier.NodeとModifier.Elementの関係を理解する

この記事をシェア

Jetpack Composeのパフォーマンス改善のためにModifier.composedからModifier.Nodeへの移行が進められています。自分の作ったライブラリもModifier.Nodeに移行したいと思って調べ始めたのですが、インターフェースや抽象クラスがたくさん出てきて全体像を把握するのが難しかったので、Modifier.ElementModifier.Nodeといった登場人物の関連を整理して、全体の構成を俯瞰できるようにしてみました。私も調べながらこの記事を書いているので、もし間違いがあったらTwitterなどでご指摘いただけるとありがたいです。

Modifier.ElementとModifier.Nodeの関係

まず、Modifier.ElementModifier.Nodeについて理解しておきたい前提があります。Modifier.Elementは、Modifierチェーンを構成する要素です。Modifierチェーンとは、Modifier.fillMaxSize().clickable{}.background()....のようにModifier修飾子をつなげた構造のことで、このチェーンの一つ一つがModifier.Elementで構成されています。しかし、Modifier.Elementが直接UIの描画に使われるわけではありません。一つのModifier.Elementにつき、一つのModifier.Nodeが作成され、これがLayoutに適用されることによってUIに反映されます。

このModifier.ElementModifier.Nodeの関係は、Android Dev Summit 2022の動画で説明されています。

動画から2つのスライドを引用します。

Modifier.Elementでチェーンが構成され・・・

個々のModifier.ElementからModifier.Nodeが作成され、Layoutに適用されます。

クラス構成

では、この前提を踏まえた上で、Modifier.NodeModifier.Elementの周辺のクラス図を見ていきます。

最上位に位置するのは、Modifierインターフェースです。Modifierには、allanyfoldInfoldOutといったModifierチェーンを実現するためのメソッドが定義されています。

Modifierを継承しているのが、Modifier.Elementインターフェースです。Modifier.ElementはModifierチェーンを構成する個々の要素で、allanyfoldInfoldOutのデフォルト実装を提供しています。(Kotlinのインターフェースって、メソッドの実装を書けるんですね。)

そして、Modifier.Elementの実装(の一つ)が、ModifierNodeElementです。ただしこれは抽象クラスなので、実際に使う時はModifierNodeElementをさらに継承したクラスを作ることになります。Modifier.Node対応済みのModifier修飾子(Modifier.fillMaxSizeModifier.clickableなど)は、ModifierNodeElementのサブクラスのオブジェクトを返します。ModifierNodeElementは間接的にModifierインターフェースを実装しているので、Modifierチェーンの要素になることができるのです。

ModifierNodeElementと1対1で対応するのが、Modifier.Nodeです。Modifier.Nodeも抽象クラスなので、実際にはこのサブクラスを作成して使います。ModifierNodeElement.create()Modifier.Nodeオブジェクトを作成します。作成されたModifier.Nodeが、Layout関数でUIに適用されます。Modifier.NodeonAttachonDetachは、Layoutの処理に関連して呼び出されます。

Modifier.Elementupdateメソッドが定義されているのがポイントで、Modifier.Node対応がパフォーマンス改善につながる所以です。UIの状態が更新されたとき、ModifierNodeElementupdateメソッドでModifier.Nodeを更新します。長々としたModifierチェーンを一から構成しなおすのではなく、変更があった部分だけを更新することでパフォーマンスを改善しています(だと思います)。

Modifier.Nodeは、DelegatableNodeインターフェースを実装しています。delegateは「委譲する、まかせる」という意味で、DelegatableNodeは「まかせられる側」です。Modifier.NodeDelegatableNodeを実装しているので、あるModifier.Nodeから別のModifier.Nodeに処理を任せることができます。これによって、既存のModifier.Nodeを組み合わせて複雑なModifierを実装することができます。


以上、今回はModifier.NodeModifier.Elementを中心に、その周辺のインターフェースやクラスの関係性について整理しました。今後、具体的な実装例なども紹介できればいいなと思っています。

この記事をシェア