Android Studio 3.6 Canary 11 で ViewBinding を使えるようになりました
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 クラスが生成されています。