MVVM + Databinding was used as the main architecture for one of the company’s reconstruction projects. This architecture is more front-end style, lighter and smarter than previous MVP, and also conforms to the idea of FLUTTER. The key is to bind data to THE UI, and the UI changes are driven by data. Much less get() set(), wySIWYG is what you get
Start databindding on Gradle for Android. Databinding is Google’s official library, so this line automatically integrates the relevant code:
dataBinding {
enabled true
}
Copy the code
Binding class generation and use
There are several different ways to initialize the injection binding in your project’s activity, depending on your project’s needs
- 1. Modify the BaseActivity class, suitable for the new project, use DataBindingUtil. The setContentView
The ActivityDemoBinding class is automatically generated by databinding from an XML file, just like ButterKnife
activity_demo.xml :
- 2. Bind XML directly in the Activity implementation class, which is the same Activity as above. This time, the original project structure is not changed, and bind XML in demoActivity, which is suitable for modification on the basis of the original project
Actually DataBindingUtil. Finally the setContentView method is also called the bind () method to bind the layout, but first in the previous step calls the setContentView activity
DataBindingUtil.setContentView :
Build the ViewModel
The corresponding ViewModel object is then generated in the specific activity
@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.bind(getContainerView());
mBinding.setModel(new DemoViewModel());
}
Copy the code
Declare some data in the viewModel:
public class DemoViewModel {
public ObservableField<String> demoString = new ObservableField<>("");
public ObservableBoolean demoBoolean = new ObservableBoolean();
public ObservableInt demoNum = new ObservableInt();
public void onButtonClick(View v){
//TODO
}
}
Copy the code
ObservableInt is a databinding class that encapsulates some basic data types. ObservableInt can also be customized to encapsulate its own classes. It mainly implements the listener callback interface, uses the observer mode, and notifies the bound View to refresh the UI when data changes
Android typically obtains views using a butterKnife or, more primitive, findviewById(). This method is redundant. For example, with a handy butterKnife, you must declare the View object, the View type, and the View ID on Acelasticity. Using databinding, you can get the mapping class of the XML layout directly. Using a Binding object, you can use it directly in an Activity without declaring it. Even simple operations such as setting text, images, and clicking events do not require Activity intervention. You bind specific data or methods directly in XML.
Use method, in XML:
<? The XML version = "1.0" encoding = "utf-8"? > <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="model" type="com.XXX.DemoViewModel" /> <import type="android.view.View"/> </data> <FrameLayout android:id="@+id/container_demo" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/tv_demo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{model.demoString}" android:visibility="@{model.demoBoolean? View.VISIBLE : View.GONE}" /> <Button android:id="@+id/bt_demo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="@{model::onButtonClick}" /> </FrameLayout> </layout>Copy the code
Add the Layout tag to the root layout, add the Data tag, and type is the viewModel created by the baseActivity above
The most basic textView shows:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF4A4A4A"
android:textSize="18sp"
android:drawablePadding="10dp"
android:text="@{model.demoString,default= 123}"
/>
Copy the code
editext
<EditText
android:layout_width="match_parent"
android:layout_weight="1"
...
android:text="@={viewModel.phoneNo}"
binding:textChanged="@{viewModel.textChangeCommand}"
/>
Copy the code
The difference between “@{}” and “@={}” is that the “@{}” is unidirectional and notifies the UI of changes in data, while the “@={}” is bidirectional and notifies the UI of changes in data, typically the Edittext input box
If you use the primitive method, such as findViewById or Butteknife, to declare a View object at the start of your activity, you need to use the VIEW ID and type, and click events need to be added one by one, otherwise the click won’t work. GetText ().toString() is used in the input box to get user input data. It is very tedious. Any error in the input box will cause bugs to appear and affect all subsequent operations. You don’t need to declare a View object in your activity, you don’t need to worry about the type of View, you don’t need to worry about the ID of the View, you just need to bind data to the View in XML, and thanks to the bindingAdapter, you can also do some intermediate operations, such as preventing quick clicks. Load network pictures, etc., simplify many steps into one step
3. BindingAdapter
Like in normal development, we don’t just use the basic properties of the View, so in a custom View, ImageView loads the web image or something like that, we still need to get the View object and do something in Java or Kotlin code, is there a way to do that in databinding, The BindingAdapter is a View adapter that uses the AOP pattern and generates code at compile time to modify the Binding class to use a DADpter View
For example, if an Imageview is used to set the avatar, the common method is to grab the Imageview object and use Glide or some other image request framework to load the Url. Dababinding looks like this:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
binding:url="@{model.imgUrl}"
binding:placeholderRes="@drawable/bg1"
/>
Copy the code
Binding :url Specifies the image address
Binding :placeholderRes
So how do we do that? We’re going to introduce a bindingAdapter, right
@BindingAdapter(value = {"url", "placeholderRes"}, requireAll = false) public static void setImageUri(ImageView imageView, String url, int placeholderRes) { if (! Glide. With (imageView.getContext()).load(url).apply(new) RequestOptions().placeholder(placeholderRes)) .into(imageView); }}Copy the code
There is @bindingAdapter annotation, value is URL and placeholder, requireAll requires all parameters, ImageView specifies the view type, and Glide requests the web image. Placeholder image, configure a place of code that can be used in all imageViews.
There are also many common methods, such as rounded corners of the control, display different images according to different types, press to change the background, list item animation, list delimiter… And so on can be used Adapter to complete, greatly reduce the amount of code in the Activity, and can unify the format problem, change a place, everywhere
Note that the BindingAdapter will take effect if it is written anywhere in the project. Since the AOP schema is used, the code will be checked at compile time and will not be repeated. When the BindingAdapter conflicts with the original attributes in the XML, the Settings in bindingDadpter will override the original attributes
Use notes
Advantages:
The amount of code is greatly reduced
Bindingadapter unified