表現力豊かなコトリン。 拡張機能

繰り返し可能なコードが好きな人はいません。 それにもかかわらず、この非常に再現性にもかかわらず、根付いてきて長い間プログラミングに根ざした構造があります。

Androidには、このような一般的に使用されるデータバインディングコンストラクトがあります。



fun bindCell1(view: View, data: Data) { view.cell1_text.setText(data.titleId) view.cell1_icon.setImageResource(data.icon) }
      
      





明らかな方法は、私にとって非常に面倒なずさんな方法ですが、毎回ビューリンクを指定することです。 およびデータ。 各行には10文字が含まれていますが、これは明らかです。



そして、Kotlinにはこのずさんな回避策があります-拡張機能。 それらについての詳細はこちらをご覧ください



記事への簡単な注釈
この記事では、誰かに特定のプログラミングスタイルを教え込むつもりはありません。 一般的なタスクの例として、Kotlinの言語機能を示したいだけです。 Kotlinを使用しなくても、この問題を好きなように解決できます。 コメントではホリバーを控えてください-これは純粋に技術的な記事です。



メソッドをデータクラスの拡張として実装します。

デザインを



 fun Data.bindCell1(view: View) { view.cell1_icon.setImageResource(icon) view.cell2_text.setText(titleId) }
      
      





どう? bindSomeメソッドはそれ自体ではなく、データクラスの拡張です。 このメソッドは、Dataクラス自体のメソッドのように動作することがわかります。 1つの制限があります-保護されたエンティティとプライベートエンティティは拡張機能に表示されません-実際には拡張機能はクラス自体に登録されていないため、論理的です。 ただし、内部プロパティとパブリックプロパティを組み合わせると、非常に安全な組み合わせを取得できます。 したがって、Dataインスタンス自体のプロパティに直接アクセスできるようになりました。



次に、 ビューの prefixを削除してみましょう 。 これを行うには、不変のプロパティを作成します



 val Data.bindMethod_cell_2: View.() -> Unit get() = { cell2_icon.setImageResource(icon) cell2_text.setText(titleId) }
      
      





どうして?



現在、bindMethodプロパティはMediaDataクラスの拡張機能であり、同時にデータの種類によってはView!の拡張機能です。



それでは、次は何ですか?



そして、Viewを引数として渡しながら、このコンストラクトを通常のメソッドとして呼び出すことができます!



 data.bindMethod(view)
      
      





さらに先に進むと、View。()-> Unitを引数として渡すことができます。



これにより何が得られますか?



たとえば、RecyclerViewオブジェクトを単語から類型化することはまったくできず、レイアウトIDと結果のバインディング関数のみをそれに渡すことができます。 当初、bindSome(ビュー:ビュー、データ:データ)関数は厳密に型指定されていましたが、このデータ型にまったく依存しなくなりました。 -データ型(View。()-> Unit)は、Viewのみにバインドされます。



そして、名前空間の交差点?



ビューとデータ内のプロパティ名が一致すると発生します。 純粋に技術的には、これはすべて回避できます(レイアウトの名前にプレフィックスを追加できます)が、単純なパスに従うこともできます。



 val Data.bindMethod_cell_1: View.() -> Unit get() = { this.cell1_icon.setImageResource(this@bindMethod_cell_1.icon) this.cell1_text.setText(this@bindMethod_cell_1.titleId) }
      
      





デザインが長く出たということです。



しかし、引数についてはどうですか?



bindMethodに引数がある場合、このメソッドが呼び出されると、Viewオブジェクトが最初の引数として渡され、その後、通常のように残りの引数が渡されます。



 val Data.bindMethod: (View.(Int, String)->Unit) get() = { intValue, str -> view.numText.text = str.replace("%s", intValue.toString()) } //-------------------------------------- data.bindMethod.invoke(view, 0, "str%s")
      
      







このメソッドを使用すると、すべてのバインディングメソッドを1か所で収集できます。たとえば、次のようにします。



別のドキュメントの例
 class Data( val name:String, val icon:String) //----------------------------------- // DataExtensions.kt fun Data.carAdapter() = Pair<Int, View.()->Unit>( R.layout.layout_car_cell, { carcell_title.text = name carcell_icon.setImage(icon) }) fun Data.motoAdapter() = Pair<Int, View.()->Unit>( R.layout.layout_moto_cell, { moto_icon.setImage(icon) })
      
      





carAdapterとmotoAdapterはDataクラス内にないことに注意してください。 それらはどこにでも配置することができます-あなたが望む、拡張子に持って行く、あなたが望む、クラスでそれを残す。 どこからでも呼び出すことができ、拡張機能はクラスのようにインポートされます。



この記事で使用した資料は、 小さなプロジェクトにまとめました



All Articles