本文链接:https://blog.csdn.net/feather_wch/article/details/131819166
1、目前安卓常用设计模式有MVC、MVP、MVVM
2、MVC
翻遍了整个安卓开发文档,都没有说安卓是mvc的。
但是Android就是MVC的
3、MVVM中VM和ViewModel什么关系?
4、DataBinding的作用是什么?
5、双向绑定和单向绑定
例如,假设有一个 ViewModel 中的属性 name
,我们想将其绑定到一个 TextView 上:
android:text="@{user.name}"
,这会将 name
属性的值展示在 TextView 上,当 name
的值发生变化时,TextView 会自动更新。android:text="@={user.name}"
,这除了在单向绑定的基础上将 name
的值展示在 TextView 上,还可以在用户编辑 TextView 的内容时,将更改的内容反映回 name
属性。6、Java版本User类
package com.personal.tax;
import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
public class User extends BaseObservable {
String name;
int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
@Bindable
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
notifyPropertyChanged(BR.age);
}
}
7、kt版本Student类
// 不可行
class Student : BaseObservable(){
var name:String? = null
// get,不能用@Bindable注解,怎么办?
get(){
return field
}
}
// 可行
class Student{
val name:ObservableField<String> by lazy{ ObservableField<String>()}
val age:ObservableField<Int> by lazy{ ObservableField<Int>()}
}
8、DataBinding中报错,95%是布局xml错误
9、设置点击事件
//MyViewModel.java
public void appendNumber(String number){
xxx
}
xml中设置DataBinding的点击事件
Android:click=“@{()->vm.appendNumber(String.valueOf(1))}”
1、DatBinding的布局是如何处理的?
2、DataBinding会将原有布局拆分
activity_main_view.xml
分为activity_main_view-layout.xml
和activity_main_view.xml
activity_main_view.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="user"
type="com.personal.tax.User" />
data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainViewActivity">
<TextView
android:id="@+id/name_txt"
android:text="@{user.name}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/age_txt"
android:text="@{user.age}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
androidx.constraintlayout.widget.ConstraintLayout>
layout>
拆分后的DataBinding布局
// 目录:build\intermediates\data_binding_layout_info_type_merge\release\out\activity_main_view-layout.xml
<Layout directory="layout" filePath="app\src\main\res\layout\activity_main_view.xml"
isBindingData="true" isMerge="false" layout="activity_main_view"
modulePackage="com.personal.tax" rootNodeType="androidx.constraintlayout.widget.ConstraintLayout">
<Variables name="user" declared="true" type="com.personal.tax.User">
<location endLine="8" endOffset="42" startLine="6" startOffset="8" />
Variables>
<Targets>
<Target tag="layout/activity_main_view_0"
view="androidx.constraintlayout.widget.ConstraintLayout">
<Expressions />
<location endLine="32" endOffset="55" startLine="11" startOffset="4" />
Target>
<Target id="@+id/name_txt" tag="binding_1" view="TextView">
<Expressions>
<Expression attribute="android:text" text="user.name">
<Location endLine="18" endOffset="38" startLine="18" startOffset="12" />
<TwoWay>falseTwoWay>
<ValueLocation endLine="18" endOffset="36" startLine="18" startOffset="28" />
Expression>
Expressions>
<location endLine="22" endOffset="54" startLine="16" startOffset="8" />
Target>
<Target id="@+id/age_txt" tag="binding_2" view="TextView">
<Expressions>
<Expression attribute="android:text" text="user.age">
<Location endLine="26" endOffset="37" startLine="26" startOffset="12" />
<TwoWay>falseTwoWay>
<ValueLocation endLine="26" endOffset="35" startLine="26" startOffset="28" />
Expression>
Expressions>
<location endLine="30" endOffset="54" startLine="24" startOffset="8" />
Target>
Targets>
Layout>
拆分后的View xml布局
// 目录:\build\intermediates\incremental\release\mergeReleaseResources\stripped.dir\layout\activity_main_view.xml
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainViewActivity" android:tag="layout/activity_main_view_0" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools">
<TextView
android:id="@+id/name_txt"
android:tag="binding_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/age_txt"
android:tag="binding_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
androidx.constraintlayout.widget.ConstraintLayout>
3、variable的作用是什么?建立绑定
<data>
<variable
name="user"
type="com.personal.tax.User" />
</data>
4、DataBindingUtil.setContentView流程
#【DataBindingUtil】
setContentView() {
-->activity.setContentView(layoutId);
-->decorView = activity.getWindow().getDecorView();
-->contentView = decorView.findViewById(android.R.id.content);
-->bindToAddedViews(xxx, contentView, 0, layoutId)
-->bind(xxx, childView, layoutId)
-->sMapper.getDataBinder();
#【DataBinderMapperImpl】- 找到apt生成的
-->getDataBinder(xxx, View view, int layoutId)
-->tag = view.getTag(); // TAG 找到 目标布局
-->if ("layout/activity_main_view_0".equals(tag)) return new ActivityMainViewBindingImpl(component, view);
#【ActivityMainViewBindingImpl】
-->mapBindings(xxx, 3, xxx) // 3代表有3个tag
-->两个layout对应解析,生成Object[] // 大量消耗性能
--> 构造方法()
-->super(xxx, root, 1, (android.widget.TextView)bindings[2], (android.widget.TextView)bindings[1]); // 静态代码块绑定控件
#【ViewDataBinding】
-->静态代码块中:OnAttachStateChangeListener()->binding.mRebindRunnable.run() // 控件只要变化就会执行Runnable,100个控件100个Runnable执行
|———————————————控件改变后触发———————————————————|
|-->mRebindRunnable.run()
| -->executePendingBindings();
| #【ActivityMainViewBindingImpl】
| -->executeBindings()
| -->this.ageTxt.setText(userAge);
| -->双向绑定@={user.name} 特殊处理:给控件设置监听器XXXBindingAdapter,一但修改控件,就拿到值,修改到其他控件中。
-->this.mboundView0 = (androidx.constraintlayout.widget.ConstraintLayout) bindings[0];
-->this.mboundView0.setTag(null);
--》this.ageTxt.setTag(null);
this.nameTxt.setTag(null);
setRootTag(root);
// listeners
invalidateAll();
5、Databinding耗时点:
OnAttachStateChangeListener()->binding.mRebindRunnable.run()
// OnAttachStateChangeListener()是View的接口
6、binding.lifecycleOwner = this
lifecycleOwner.getLifecycle().addObserver(this.mOnStartListener);
OnStartListener
@OnLifecycleEvent(Event.ON_START)
->public void onStart() {
-->dataBinding = (ViewDataBinding)this.mBinding.get();
-->dataBinding.executePendingBindings();
-->会遍历绑定请求队列,计算所有待处理的绑定表达式,并将结果应用于View
7、为什么会有待处理的绑定请求?
dataBinding.executePendingBindings()
时会立即执行所有待处理的绑定请求1、为什么双向绑定不会死循环
2、type="com.personal.tax.User"这里全类名是使用的反射吗?