Edited at

ViewBinding が使えるようになった!

Android Studio 3.6 Canary 11 で ViewBinding を使えるようになりました :clap:

ドキュメント


ViewBinding とは?

簡易版 DataBinding のようなイメージで、findViewById を省略でき、Null Safe & Type Safe になっています。

DataBinding とは異なり、マッピングや双方向バインディングはできません。

private lateinit var binding: ActivityMainBinding

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

binding.button.setOnClickListener {
// Do something
}
}


ViewBinding を使う場面


In most cases, view binding replaces findViewById.


findViewById や Kotlin Android Extensions の置き換えが考えられます。

Kotlin Android Extensions を使う場合、id がそのまま変数名になっていたので、id を snake_case にすると View の変数名も snake_case になってました。

ViewBinding では id を snake_case にしても ViewBinding 経由で View を取得する際は lowerCamelCase になります。



Note: If you have already enabled data binding in a module, you don't need to enable view binding for that module.


DataBinding 経由で View にアクセスできるので、DataBinding を使用していれば ViewBinding を使うことはおそらくないはずです。


ViewBinding の現状の問題点


  • 一部のライブラリでサポートされていない

    出たばかりなので、groupie など一部のライブラリがサポートされていません


  • Activity のコンストラクタに渡せない

    Activity のコンストラクタにレイアウトリソースを渡すことができますが、ViewBinding との併用ができなさそうです…

    (できる方法があれば教えていただきたい…)



おまけ : ViewBinding が生成するコード

public final class ActivityVideoDetailBinding implements ViewBinding {

@NonNull
private final CoordinatorLayout rootView;

@NonNull
public final FrameLayout detailContainer;

@NonNull
public final FrameLayout playerContainer;

private ActivityVideoDetailBinding(@NonNull CoordinatorLayout rootView,
@NonNull FrameLayout detailContainer, @NonNull FrameLayout playerContainer) {
this.rootView = rootView;
this.detailContainer = detailContainer;
this.playerContainer = playerContainer;
}

@Override
@NonNull
public CoordinatorLayout getRoot() {
return rootView;
}

@NonNull
public static ActivityVideoDetailBinding inflate(@NonNull LayoutInflater inflater) {
return inflate(inflater, null, false);
}

@NonNull
public static ActivityVideoDetailBinding inflate(@NonNull LayoutInflater inflater,
@Nullable ViewGroup parent, boolean attachToParent) {
View root = inflater.inflate(R.layout.activity_video_detail, parent, false);
if (attachToParent) {
parent.addView(root);
}
return bind(root);
}

@NonNull
public static ActivityVideoDetailBinding bind(@NonNull View rootView) {
// The body of this method is generated in a way you would not otherwise write.
// This is done to optimize the compiled bytecode for size and performance.
String missingId;
missingId: {
FrameLayout detailContainer = rootView.findViewById(R.id.detailContainer);
if (detailContainer == null) {
missingId = "detailContainer";
break missingId;
}
FrameLayout playerContainer = rootView.findViewById(R.id.playerContainer);
if (playerContainer == null) {
missingId = "playerContainer";
break missingId;
}
return new ActivityVideoDetailBinding((CoordinatorLayout) rootView, detailContainer,
playerContainer);
}
throw new NullPointerException("Missing required view with ID: ".concat(missingId));
}
}

ただ findViewById をして変数で持っていてくれる Binding クラスが生成されています。