从MVC—>MVP—>MVVM,框架在不断的转变,接下来介绍MVVM的使用
MVVM
Model:代表基本的业务逻辑
View:显示内容
ViewModel:将前面两者联系在一起,一个ViewModel和一个View匹配,它没有MVP中的IView接口,而是完全和View绑定,所有View中的修改变化,都会自动更新到ViewModel中,同时ViewModel的任何变化也会自动同步到View上。
DataBinding
在使用MVVM这个框架之前,要先知道DataBinding的基本使用,DataBinding可以将View和一个对象的field绑定,当field更新的时候,framework将收到通知,然后View自动更新。
DataBinding的使用
一、在build.gradle里,像下面这样就设置好了
android{
……
dataBinding {
enabled = true
}
}
二、布局、代码和运行结果如下:
布局最外围是layout,不再是五大布局,里面是data,variable里 name的名字可以自己随便的取,type是填写bean的包名;布局里有两个TextView, 在text="@{girlFriend.name}" 这个里面通过@{名称.变量名}的方式进行绑定。
ActivityMainBinding、DataBindingUtil是自动生成的,不在是setContentView(R.layout.activity_main);而是通过DataBindingUtil.setContentView的方式,将布局放入这个方法,方法内部会遍历这个布局所有的字View元素,达到与数据所对应
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
//ActivityMainBinding、DataBindingUtil是自动生成的,不在是setContentView(R.layout.activity_main);而是
//通过DataBindingUtil.setContentView的方式,将布局放入这个方法内部会遍历这个布局所有的字View元素,达到与
//数据所对应
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
GirlFriend girlFriend = new GirlFriend();
girlFriend.name = "Maria";
girlFriend.country = "外国";
binding.setGirlFriend(girlFriend);
}
}
这个是Bean类,类里就两个变量name和country
public class GirlFriend {
public String name;
public String country;
}
运行的结果:
三、到这里DataBinding的最、最、最基本的用法讲完了,与之前不一样是布局用layout,设置data,通过@{名称.变量名}的方式进行绑定,而代码中不再是通过setContentView而是通过DataBindingUtil.senContentView。从上面可以看到的是代码运行在主线程中,这也很好理解。因为改变UI必须在主线程中,那如果是在子线程中改变UI会怎么样呢?下面是修改过的代码和运行结果:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
//ActivityMainBinding、DataBindingUtil是自动生成的,不在是setContentView(R.layout.activity_main);而是
//通过DataBindingUtil.setContentView的方式,将布局放入这个方法内部会遍历这个布局所有的字View元素,达到与
//数据所对应
final ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
final GirlFriend girlFriend = new GirlFriend();
girlFriend.name = "Maria";
girlFriend.country = "外国";
binding.setGirlFriend(girlFriend);
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(3000);
girlFriend.name = "Maria and 罗宾";
binding.setGirlFriend(girlFriend);
}
}).start();
}
}
可以看到是在子线程更新UI居然是可以的!!!至于为什么可以以后会继续讲解DataBinding的原理,上面在子线程更新UI也可以换种写法,首先修改Bean类
Bean类:
public class GirlFriend {
// public String name;
// public String country;
public ObservableField name = new ObservableField<>();
public ObservableField country = new ObservableField<>();
}
Activity中代码修改:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
//ActivityMainBinding、DataBindingUtil是自动生成的,不在是setContentView(R.layout.activity_main);而是
//通过DataBindingUtil.setContentView的方式,将布局放入这个方法内部会遍历这个布局所有的字View元素,达到与
//数据所对应
final ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
final GirlFriend girlFriend = new GirlFriend();
girlFriend.name.set("Maria");
girlFriend.country.set("外国");
binding.setGirlFriend(girlFriend);
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(3000);
girlFriend.name.set("Maria and 罗宾");
// binding.setGirlFriend(girlFriend);
}
}).start();
}
}
不一样的是采用new ObservableField<>()的方式出来变量名,而在子线程中也只要重写设置name名就行,因为使用ObservableField时,更新UI的时候,会去通过framework层去更新UI,所以无需在通过binding.setGirlFriend(),运行结果是一样的,这里不再贴出。
四、实现点击事件,采用@{名称::方法名}或@{名称.方法名}的方式,还是上面的代码修改如下:
布局里:TextView里添加android:onClick="@{girlFriend::ClickOnListener}"进行监听
Bean类修改如下,注意的是ClickOnListener方法里要加(View view)不然会报错的,运行结果如下
public class GirlFriend {
// public String name;
// public String country;
private Context mContext;
public ObservableField name = new ObservableField<>();
public ObservableField country = new ObservableField<>();
public GirlFriend(Context context) {
this.mContext = context;
}
public void ClickOnListener(View view) {
Toast.makeText(mContext, "点击了", Toast.LENGTH_SHORT).show();
}
}
五、如果想点击TextView的时候实现TextView的文本内容进行变化,也是可以做到的,还是上面的代码进行修改,如下:
可以直接在Bean类中改,textView.setText("Maria and 罗宾 and 娜美"),运行结果这里就不贴出了。
public class GirlFriend {
// public String name;
// public String country;
private Context mContext;
public ObservableField name = new ObservableField<>();
public ObservableField country = new ObservableField<>();
public GirlFriend(Context context) {
this.mContext = context;
}
public void ClickOnListener(View view) {
TextView textView = (TextView) view;
textView.setText("Maria and 罗宾 and 娜美");
Toast.makeText(mContext, "点击了", Toast.LENGTH_SHORT).show();
}
}
六、DataBinding用法还有很多,其他的后期继续讲,下面结合MVVM框架来讲解,还是用上面的代码,修改代码如下:
① 类放置结构 创建包mode、view、viewmodle,将类GirlFriend放置到model包中,将MainActivity放置到view中,在包viewmodel中创建MainViewModel类
布局代码:在EditText中添加android:addTextChangedListener = "@{ViewModel.accChange}",进行监听文本改变
MainViewModel代码:
public class MainViewModel {
private Context mContext;
public String acc;
public String pwt;
public ObservableField login = new ObservableField<>();
public MainViewModel(Context mContext) {
this.mContext = mContext;
login.set("登陆");
}
//进行监听
public TextWatcher accChange(){
return new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
acc = s.toString();
}
@Override
public void afterTextChanged(Editable s) {
}
};
}
//进行监听
public TextWatcher pwtChange(){
return new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
pwt = s.toString();
}
@Override
public void afterTextChanged(Editable s) {
}
};
}
//登陆监听
public void loginButton(View view) {
if (!TextUtils.isEmpty(acc) && !TextUtils.isEmpty(pwt)) {
Toast.makeText(mContext, "登陆成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(mContext, "请输入密码或账号", Toast.LENGTH_SHORT).show();
}
}
}
MainActivity代码:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
//ActivityMainBinding、DataBindingUtil是自动生成的,不在是setContentView(R.layout.activity_main);而是
//通过DataBindingUtil.setContentView的方式,将布局放入这个方法内部会遍历这个布局所有的字View元素,达到与
//数据所对应
ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
MainViewModel mainViewModel = new MainViewModel(this);
binding.setViewModel(mainViewModel);
}
}
运行结果:
这么没有用到model包中的类,因为这里只是模仿登陆功能,并不需要用到,后面会讲到,本人小白,若有问题欢迎提出。
微信公众号:猿味生活 欢迎关注,一起成长