I use Android Studio 3.6-RC1 and build tools version 3.6.0-rc01 and encountered an issue with ViewBinding feature:
I have activity_test.xml file with the following markup:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/view_merged"
layout="@layout/merge_view" />
</LinearLayout>
And merge_view.xml with following markup:
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Merge view" />
</merge>
Activity code looks like the following:
class TestActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityTestBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.viewMerged.label.text = "New text"
}
}
Problem is when I try to access TextView from merged layout, the app throws an exception with the message java.lang.NullPointerException: Missing required view with ID: viewMerged.
The generated binding class looks like the following:
public final class ActivityTestBinding implements ViewBinding {
@NonNull
private final LinearLayout rootView;
@NonNull
public final MergeViewBinding viewMerged;
private ActivityTestBinding(@NonNull LinearLayout rootView,
@NonNull MergeViewBinding viewMerged) {
this.rootView = rootView;
this.viewMerged = viewMerged;
}
@Override
@NonNull
public LinearLayout getRoot() {
return rootView;
}
@NonNull
public static ActivityTestBinding inflate(@NonNull LayoutInflater inflater) {
return inflate(inflater, null, false);
}
@NonNull
public static ActivityTestBinding inflate(@NonNull LayoutInflater inflater,
@Nullable ViewGroup parent, boolean attachToParent) {
View root = inflater.inflate(R.layout.activity_test, parent, false);
if (attachToParent) {
parent.addView(root);
}
return bind(root);
}
@NonNull
public static ActivityTestBinding 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: {
View viewMerged = rootView.findViewById(R.id.view_merged);
if (viewMerged == null) {
missingId = "viewMerged";
break missingId;
}
MergeViewBinding viewMergedBinding = MergeViewBinding.bind(viewMerged);
return new ActivityTestBinding((LinearLayout) rootView, viewMergedBinding);
}
throw new NullPointerException("Missing required view with ID: ".concat(missingId));
}
}
Am I missing something or there is no way to access views from included layouts with tags or it is not yet shipped in Android Studio 3.6-RC1?
To efficiently re-use complete layouts, you can use the <include/> and <merge/> tags to embed another layout inside the current layout. Reusing layouts is particularly powerful as it allows you to create reusable complex layouts.
RelativeLayout : is a ViewGroup that displays child views in relative positions.
Palette: Contains various views and view groups that you can drag into your layout.
I wrote an article about using ViewBinding with <merge>
tag which you can find here
Basically, what you need to do is
<include>
tag any ID.bind()
method of generated merge layout binding, passing the root view of the layout you included your layout in.For example, you have merge_view.xml
so you'll have MergeViewBinding
class generated and this is how you will access the view from this layout.
class TestActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityTestBinding.inflate(layoutInflater)
val mergeBinding = MergeViewBinding.bind(binding.root)
setContentView(binding.root)
mergeBinding.label.text = "New text"
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With