web-dev-qa-db-ja.com

Kotlin Android View Binding:findViewById vs Butterknife vs Kotlin Android Extension

私は最善の方法を見つけようとしていますAndroid Kotlinのビューバインディング。そこにはいくつかのオプションがあるようです。

findViewById

val button: Button by lazy { findViewById<Button>(R.id.button) }

バターナイフ

https://github.com/JakeWharton/butterknife

@BindView(R.id.button) lateinit var button: Button

Kotlin Android Extensions

https://kotlinlang.org/docs/tutorials/Android-plugin.html

import kotlinx.Android.synthetic.main.activity_main.*

私はJava landのfindViewByIdとButterknifeにかなり精通していますが、Kotlinの各ビューバインディングアプローチの長所と短所は何ですか?

Kotlin Android Extensionsは、RecyclerView + ViewHolderパターンでうまく機能しますか?

また、Kotlin Android拡張機能は、includeを介してネストされたビューのビューバインディングを処理しますか?

例:activity_main.xmlを使用するアクティビティの場合、View custom1にどのようにアクセスしますか?

activity_main.xml

<...>
    <include layout="@layout/custom" Android:id="@+id/custom" />
</>

custom.xml

<...>
    <View Android:id="@+id/custom1" ... />
    <View Android:id="@+id/custom2" ... />
</>
20
triad

_kotlin-Android-extensions_はKotlinに適しています。 ButterKnifeも優れていますが、ここでは_kotlin-Android-extensions_の方が賢明な選択です。

理由Kotlinsyntheticプロパティを使用し、_caching function_を使用してオンデマンドで呼び出されますButterKnifeは、ButterKnife.bind()(少し時間がかかる)で一度にすべてのビューをバインドしますが、アクティビティ/フラグメントの読み込み)。 Kotlinを使用すると、ビューをバインドするために注釈を使用する必要さえありません。

はい、RecyclerView + ViewHolderパターンとも良好に動作します。インポートする必要があるのは、_kotlinx.Android.synthetic.main.layout_main.view.*_(if _layout_main.xml_がアクティビティ/フラグメントレイアウトファイル名の場合)です。

includeを使用してインポートされたレイアウトに対して、追加の作業を行う必要はありません。インポートされたビューのIDを使用するだけです。

次の公式ドキュメントノートをご覧ください。

Kotlin Android ExtensionsはKotlinコンパイラのプラグインであり、次の2つのことを行います。

  1. 各Kotlinアクティビティ内に非表示のキャッシュ機能とフィールドを追加します。メソッドは非常に小さいため、APKのサイズはあまり増加しません。
  2. 各合成プロパティ呼び出しを関数呼び出しに置き換えます。

    これがどのように機能するかは、レシーバーがモジュールソースにあるKotlin Activity/Fragmentクラスである合成プロパティを呼び出すときに、キャッシュ機能が呼び出されることです。たとえば、与えられた

_class MyActivity : Activity()
fun MyActivity.a() { 
    this.textView.setText(“”)
}
_

myActivity内に非表示のキャッシュ関数が生成されるため、キャッシュメカニズムを使用できます。

ただし、次の場合:

_fun Activity.b() { 
    this.textView.setText(“”)
}
_

この関数がソースからのアクティビティのみで呼び出されるのか、プレーンJavaアクティビティでも呼び出されるのかどうかはわかりません。そのため、MyActivityインスタンスが前の例はレシーバーです。

上記へのリンク ドキュメントページ

役に立てば幸いです。

13
chandil03

使用の世話をする

val button: Button by lazy { findViewById<Button>(R.id.button) }

ビューが破壊されたときに問題にすでに直面していますが、フラグメントのインスタンスが生き残ると(アクティビティの場合は適用されないと思います)、古いものを参照するlazyプロパティを保持しますビュー。

例:

レイアウトに静的な値がある場合、Android:text="foo"

//calling first time
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
    button.setText("bar")
    // button is called for the first time, 
    // then button is the view created recently and shows "bar"
}

次に、フラグメントを置き換えるためにフラグメントが破棄されますが、それからカムバックし、再度onCreateViewコールインを再生成しました。

//calling second after destroyed
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
    button.setText(Date().time.toString())
    //button is already set, then you are setting the value the to old view reference
    // and in your new button the value won't be assigned
    // The text showed in the button will be "foo"
}
4
crgarridos

この質問を重複としてフラグすることはできません。異なる質問の下で回答/議論された複数のことを尋ねているからです。

Kotlinの各ビューバインディングアプローチの長所と短所は何ですか?

これは議論されました here

Kotlin Android拡張機能はincludeを介してネストされたビューのビューバインディングを処理しますか?例:activity_main.xmlを使用するアクティビティの場合、View custom1はどのようにアクセスされますか?

Kotlin Android ExtensionsはfindViewByIdを呼び出すだけです。 here を参照してください。

Kotlin Android Extensionsは、RecyclerView + ViewHolderパターンでうまく機能しますか?

はい、そうです。ただし、アクティビティやフラグメントなどのキャッシュは存在しないため、そこから取得したビューをプロパティに保存する必要があります。 here を参照してください。


未回答の質問がある場合は、お気軽に質問してください。

4
zsmb13

dataindingライブラリを使用している場合。ビューバインディングをデータバインディングする必要があります。

それはkotlin-extensionsよりも明示的であるため

p.s findviewbyidは非常に不便で定型的なコードです

0
bong jae choe

4番目のオプションがあり、これはView Binding と呼ばれますAndroid Studio 3.6 Carnary 11で利用可能

docsから引用

バインディングの表示

ビューバインディングは、ビューと対話するコードをより簡単に記述できる機能です。モジュールでビューバインディングを有効にすると、そのモジュールに存在する各XMLレイアウトファイルのバインディングクラスが生成されます。バインディングクラスのインスタンスには、対応するレイアウトのIDを持つすべてのビューへの直接参照が含まれます。

ほとんどの場合、ビューバインディングはfindViewByIdを置き換えます。


findViewByIdとの違い

ビューバインディングには、findViewByIdを使用するよりも重要な利点があります。

  • ヌルの安全性:ビューのバインディングはビューへの直接参照を作成するため、無効なビューIDによるヌルポインター例外のリスクはありません。さらに、ビューがレイアウトの一部の構成にのみ存在する場合、バインディングクラスでその参照を含むフィールドは_@Nullable_でマークされます。

  • タイプセーフティ:各バインディングクラスのフィールドには、XMLファイルで参照するビューと一致するタイプがあります。これは、クラスキャスト例外のリスクがないことを意味します。


データバインディングライブラリとの違い

ビューバインディングとデータバインディングライブラリはどちらも、ビューを直接参照するために使用できるバインディングクラスを生成します。ただし、顕著な違いがあります。

  • データバインディングライブラリは、_<layout>_タグを使用して作成されたデータバインディングレイアウトのみを処理します。
  • ビューバインディングはレイアウト変数またはレイアウト式をサポートしていないため、レイアウトをXMLのデータにバインドするために使用できません。

使用法

プロジェクトのモジュールでビューバインディングを利用するには、_build.gradle_ファイルに次の行を追加します。

_Android {
    viewBinding.enabled = true
}
_

たとえば、_result_profile.xml_というレイアウトファイルがある場合:

_<LinearLayout ... >
    <TextView Android:id="@+id/name" />
    <ImageView Android:cropToPadding="true" />
    <Button Android:id="@+id/button"
        Android:background="@drawable/rounded_button" />
</LinearLayout>
_

この例では、activityResultProfileBinding.inflate()を呼び出すことができます。

_private lateinit var binding: ResultProfileBinding

@Override
fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    binding = ResultProfileBinding.inflate(layoutInflater)
    setContentView(binding.root)
}
_

バインディングクラスのインスタンスを使用して、任意のビューを参照できるようになりました。

_binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }
_
0
user158