因公司项目技术需求,开始使用LiveData+ViewModel 架构,这东西是Google 2017 IO大会新发布的官方推荐架构(Lifecycle,LiveData,ViewModel,Room,Paging,Navigation)中的一部分。关于使用LiveData+ViewModel的优点就不详细解析了,主要为以下几点:
(1)数据绑定,数据改变时,UI同步跟着改变。
(2)LiveData内部使用Lifecycle管理Activity或fragment的生命周期,只在UI活跃情况下才更新数据,不活跃情况下不更新
(3)Lifecycle管理生命周期,可避免内存泄露
具体使用:
(1)引入工程
工程的build.gradle
allprojects {
repositories {
google()
jcenter()
}
}
app 的build.gradle
implementation "android.arch.lifecycle:extensions:1.1.1"
annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
(2)创建ViewModel
public class UserModel extends ViewModel {
private MutableLiveData userLiveData = new MutableLiveData<>();
public void setUserLiveData(User user) {
this.userLiveData.setValue(user);
}
public MutableLiveData getUserLiveData() {
return userLiveData;
}
}
public class User {
private String name;
private int age;
private String sex;
private String hobby;
public User(String name, int age, String sex, String hobby) {
this.name = name;
this.age = age;
this.sex = sex;
this.hobby = hobby;
}
//getter and setter
.......
}
(3)在Activity或fragment订阅数据
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView mTextViewName;
private TextView mTextViewAge;
private TextView mTextViewSex;
private TextView mTextViewHobby;
private UserModel mUserModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button_edit_name).setOnClickListener(this);
mTextViewName = findViewById(R.id.text_view_name);
mTextViewAge = findViewById(R.id.text_view_age);
mTextViewSex = findViewById(R.id.text_view_sex);
mTextViewHobby = findViewById(R.id.text_view_hobby);
mUserModel = ViewModelProviders.of(this).get(UserModel.class);
User user = new User("超人", 10, "男", "飞来飞去");
//初始化数据
mUserModel.setUserLiveData(user);
//订阅数据
mUserModel.getUserLiveData().observe(this, new Observer() {
@Override
public void onChanged(@Nullable User user) {
mTextViewName.setText("姓名:" + user.getName());
mTextViewAge.setText("年龄:" + user.getAge());
mTextViewSex.setText("性别:" + user.getSex());
mTextViewHobby.setText("爱好:" + user.getHobby());
}
});
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_edit_name:
mUserModel.getUserLiveData().postValue(new User("奥特曼", 20, "女", "跳来跳去"));
break;
}
}
}
效果就不作展示了,具体点击按钮就能改变数据,相应的数据变化后会调用onChanged函数
使用起来相对很简单,但细心的人会注意要,上面每修改一次数据,就new一个对象出来,这在项目中是不正常的。按正常思维来说,只要直接修改对象中的数据,就能达到变化才对。所以对上面代码进行修改。
(4)修改后的ViewModel
public class UserModel3 extends ViewModel {
private MutableLiveData userLiveData = new MutableLiveData<>();
public void setUserLiveData(User user) {
this.userLiveData.setValue(user);
}
public MutableLiveData getUserLiveData() {
return userLiveData;
}
public void setValueName(String name) {
this.userLiveData.getValue().setName(name);
this.userLiveData.postValue(userLiveData.getValue());
}
public void setValueAge(int age) {
this.userLiveData.getValue().setAge(age);
this.userLiveData.postValue(userLiveData.getValue());
}
public void setValueSex(String sex) {
this.userLiveData.getValue().setSex(sex);
this.userLiveData.postValue(userLiveData.getValue());
}
public void setValueHobby(String hobby) {
this.userLiveData.getValue().setHobby(hobby);
this.userLiveData.postValue(userLiveData.getValue());
}
}
(5)使用修改后的ViewModel
public class MainActivity2 extends AppCompatActivity implements View.OnClickListener {
private TextView mTextViewName;
private TextView mTextViewAge;
private TextView mTextViewSex;
private TextView mTextViewHobby;
private UserModel3 mUserModel3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button_edit_name).setOnClickListener(this);
findViewById(R.id.button_edit_age).setOnClickListener(this);
findViewById(R.id.button_edit_sex).setOnClickListener(this);
findViewById(R.id.button_edit_hobby).setOnClickListener(this);
mTextViewName = findViewById(R.id.text_view_name);
mTextViewAge = findViewById(R.id.text_view_age);
mTextViewSex = findViewById(R.id.text_view_sex);
mTextViewHobby = findViewById(R.id.text_view_hobby);
mUserModel3 = ViewModelProviders.of(this).get(UserModel3.class);
User user = new User("超人", 10, "男", "飞来飞去");
mUserModel3.setUserLiveData(user);
mUserModel3.getUserLiveData().observe(this, new Observer() {
@Override
public void onChanged(@Nullable User user) {
mTextViewName.setText("姓名:" + user.getName());
mTextViewAge.setText("年龄:" + user.getAge());
mTextViewSex.setText("性别:" + user.getSex());
mTextViewHobby.setText("爱好:" + user.getHobby());
}
});
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_edit_name:
mUserModel3.setValueName("奥特曼");
break;
case R.id.button_edit_age:
mUserModel3.setValueAge(mUserModel3.getUserLiveData().getValue().getAge() + 1);
break;
case R.id.button_edit_sex:
mUserModel3.setValueSex("妹子");
break;
case R.id.button_edit_hobby:
mUserModel3.setValueHobby("妹子+运动");
break;
}
}
}
可以看出在新的UserModel3中,调用set...方法是先对象属性,再把修改后的对象重新赋值,这样避免频繁创建对象。
最后再简单看看LiveData的源码,源码不多,400行左右,比较容易看明白。
从更新数据调用postValue开始:
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue); //最后还是调用setValue
}
};
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++; //数据版本加一
mData = value;
dispatchingValue(null); //通知订阅者更新数据
}
private void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
//把所有订阅者找出来迭代通知
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) { //判断数据是不是更新了
return;
}
observer.mLastVersion = mVersion;
//noinspection unchecked
observer.mObserver.onChanged((T) mData); //在这里调用onChange更新数据
}