减法、减法、继续减法,之前记录了一半,最近抽时间再补全一下,仅为个人见解~
Android Architecture Components 架构组件
- 组件化之路 - LiveData一知半解
- 组件化之路 - LiveData + ViewModel一知半解
因为一直处于小厂的舒适区中,所以除了自我驱动外,一般根本不会接触到近几年的新技术,不过该庆幸的是 “吾虽未齐头奋进,但从未落地不前” ~
近几年Jetpack组件库被广泛使用,除去Kotlin的compose等相关组件外,我们首先应该掌握的还是可兼容Java Lifecycle、LiveData、ViewModel 组件套 ~
- 基本认知
- 基础实现
- 官网示例
- 自我演练
- 单串演练
- 完整Demo
其实在学习ViewModel组件前,最好是掌握了Lifecycle和LiveData组件,因为在ViewModel中看到了这俩个组件的影子!
每个人的学习方式有所不同,有的喜欢看视频,有的喜欢看blog,有的喜欢看源码,但是根据常规顺序学一样知识的时候,最先看的应该是 官方文档 - LiveData 、官方文档 - ViewModel
我不太清楚别人是如何理解 LiveData、ViewModel 的,我也不知道这么理解对不对 ?
- ViewModel 官网介绍:ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。
- ViewModel 自我理解:保留数据、视图的意外丢失,支持Activity和依赖该Activity的Fragment共享数据源
- LiveData 自我理解:可被观察的数据持有类
- LiveData+LiveData 自我理解:ViewModel分解为View、Model,主要通过数据来驱动视图,可实时监听数据变化,内部应该采用了观察者模式,这里主要是LiveData特性;涉及到生命周期的范围,一般都用到了Lifecycle
build.gradle 引入依赖
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:1.1.0"
// alternatively, just ViewModel
// implementation "android.arch.lifecycle:viewmodel:1.1.0"
// alternatively, just LiveData
// implementation "android.arch.lifecycle:livedata:1.1.0"
官网示例
注意:此示例为官网中ViewModel的使用示例,尽可借鉴,有个大概印象就好
ViewModel
public class MyViewModel extends ViewModel {
private MutableLiveData> users;
public LiveData> getUsers() {
if (users == null) {
users = new MutableLiveData>();
loadUsers();
}
return users;
}
private void loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
Activity
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// update UI
});
}
}
Fragment
public class SharedViewModel extends ViewModel {
private final MutableLiveData- selected = new MutableLiveData
- ();
public void select(Item item) {
selected.setValue(item);
}
public LiveData
- getSelected() {
return selected;
}
}
public class ListFragment extends Fragment {
private SharedViewModel model;
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends Fragment {
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SharedViewModel model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
model.getSelected().observe(getViewLifecycleOwner(), item -> {
// Update the UI.
});
}
}
自我演练
既然都说是ViewModel了,肯定是以model为单元进行演练的,但是最后我也加入了类似LiveData单字符串的调用方式 ~
TestModel
这个很常见,可以理解为model、bean这样的实体类,没什么特殊的
package com.example.livedata;
public class TestModel {
public TestModel(String name, int age) {
this.name = name;
this.age = age;
}
public TestModel() {
super();
}
public String name;
public int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
TestViewModel
这个类比较关键,是ViewModel组件实现的主体类;关于以下俩种实现方式的最终效果是一致的,主要区别在于LiveData和MutableLiveData更新数据时的使用方式,关于具体区别看我上面提到的 LiveData Blog 就好~
实现方式 1:根据官方示例 获取ViewModel时,返回的是LiveData,导致只能通过类内方法进行设值,个人不建议这么使用,虽然实现了出口统一,但是使用起来有点麻烦;不过不能一棒子打死,根据自己场景选取实现方式吧~
package com.example.livedata;
import android.util.Log;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class TestViewModel extends ViewModel {
private MutableLiveData liveData;
public LiveData getTestViewModel() {
if (liveData == null) {
liveData = new MutableLiveData();
}
return liveData;
}
public void setTestViewModel(TestModel testModel) {
liveData.postValue(testModel);
}
@Override
protected void onCleared() {
super.onCleared();
Log.e("tag","只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源");
}
}:
MainActivity
package com.example.livedata;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
public class MainActivity extends AppCompatActivity {
private TestViewModel testViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView mName = findViewById(R.id.tv_test);
testViewModel = ViewModelProviders.of(this).get(TestViewModel.class);
//接收源,当数据发生改变就会被及时监听到
testViewModel.getTestViewModel().observe(this, new Observer() {
@Override
public void onChanged(TestModel testModel) {
mName.setText("姓名:" + testModel.getName() + " - 年龄:" + testModel.age);
}
});
//发送源,改变数据的地方,此处只是示例而已
mName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
testViewModel.setTestViewModel(new TestModel("吾名:Live",19));
}
});
}
}
实现方式 2:根据对LiveData的掌握,我将获取ViewModel的返回类换MutableLiveData, 主要为了方便我自己的灵活调用> <
package com.example.livedata;
import android.util.Log;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class TestViewModel extends ViewModel {
private MutableLiveData mutableLiveData;
public MutableLiveData getTestViewModel_Mutable() {
if (mutableLiveData == null) {
mutableLiveData = new MutableLiveData();
}
return mutableLiveData;
}
@Override
protected void onCleared() {
super.onCleared();
Log.e("tag","只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源");
}
}
MainActivity
package com.example.livedata;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
public class MainActivity extends AppCompatActivity {
private TestViewModel testViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView mName = findViewById(R.id.tv_test);
testViewModel = ViewModelProviders.of(this).get(TestViewModel.class);
//接收源,当数据发生改变就会被及时监听到
testViewModel.getTestViewModel_Mutable().observe(this, new Observer() {
@Override
public void onChanged(TestModel testModel) {
mName.setText("姓名:" + testModel.getName() + " - 年龄:" + testModel.age);
}
});
//发送源,改变数据的地方,此处只是示例而已
mName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
testViewModel.getTestViewModel_Mutable().postValue(new TestModel("吾名:Live",19));
}
});
}
}
单串演练
上方主要是关于一个model的监听,这里就是仅观察一个字符串的案例,闲的没事儿尝试后记录一下,和LiveData的基本功能有点一样 ~
TestViewModel
package com.example.livedata;
import android.util.Log;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class TestViewModel extends ViewModel {
private MutableLiveData stringMutableLiveData;
MutableLiveData getAlone() {
if (stringMutableLiveData == null) {
stringMutableLiveData = new MutableLiveData<>();
}
return stringMutableLiveData;
}
@Override
protected void onCleared() {
super.onCleared();
Log.e("tag","只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源");
}
}
MainActivity
package com.example.livedata;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
public class MainActivity extends AppCompatActivity {
private TestViewModel testViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView mName = findViewById(R.id.tv_alone);
testViewModel = ViewModelProviders.of(this).get(TestViewModel.class);
//接收源,当数据发生改变就会被及时监听到
testViewModel.getAlone().observe(this, new Observer() {
@Override
public void onChanged(String data) {
mAlone.setText(data);
}
});
//发送源,改变数据的地方,此处只是示例而已
mAlone.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
testViewModel.getAlone().postValue("小小笑话可笑可笑");
}
});
}
}
完整Demo
TestModel
package com.example.livedata;
public class TestModel {
public TestModel(String name, int age) {
this.name = name;
this.age = age;
}
public TestModel() {
super();
}
public String name;
public int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
TestViewModel
package com.example.livedata;
import android.util.Log;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class TestViewModel extends ViewModel {
private MutableLiveData liveData;
private MutableLiveData mutableLiveData;
private MutableLiveData stringMutableLiveData;
public LiveData getTestViewModel() {
if (liveData == null) {
liveData = new MutableLiveData();
}
return liveData;
}
public MutableLiveData getTestViewModel_Mutable() {
if (mutableLiveData == null) {
mutableLiveData = new MutableLiveData();
}
return mutableLiveData;
}
public void setTestViewModel(TestModel testModel) {
liveData.postValue(testModel);
}
MutableLiveData getAlone() {
if (stringMutableLiveData == null) {
stringMutableLiveData = new MutableLiveData<>();
}
return stringMutableLiveData;
}
@Override
protected void onCleared() {
super.onCleared();
Log.e("tag", "只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源");
}
}
MainActivity
package com.example.livedata;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
public class MainActivity extends AppCompatActivity {
private TestViewModel testViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView mTest = findViewById(R.id.tv_test);
TextView mAlone = findViewById(R.id.tv_alone);
testViewModel = ViewModelProviders.of(this).get(TestViewModel.class);
// 数据监听
testViewModel.getTestViewModel_Mutable().observe(this, new Observer() {
@Override
public void onChanged(TestModel testModel) {
mTest.setText("姓名:" + testModel.getName() + " - 年龄:" + testModel.age);
}
});
testViewModel.getAlone().observe(this, new Observer() {
@Override
public void onChanged(String data) {
mAlone.setText(data);
}
});
// 数据发送
mTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
testViewModel.setTestViewModel(new TestModel("吾名:Live", 19));
}
});
mTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
testViewModel.getTestViewModel_Mutable().postValue(new TestModel("吾名:Live", 19));
}
});
mAlone.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
testViewModel.getAlone().postValue("小小笑话可笑可笑");
}
});
}
}



