减法、减法、继续减法,之前记录了一半,最近抽时间再补全一下,仅为个人见解~
Android Architecture Components 架构组件
因为一直处于小厂的舒适区中,所以除了自我驱动外,一般根本不会接触到近几年的新技术,不过该庆幸的是 “吾虽未齐头奋进,但从未落地不前” ~
近几年 Jetpack
组件库被广泛使用,除去 Kotlin
的 compose
等相关组件外,我们首先应该掌握的还是可兼容Java
Lifecycle、LiveData、ViewModel
组件套 ~
其实在学习ViewModel组件前,最好是掌握了Lifecycle和LiveData组件,因为在ViewModel中看到了这俩个组件的影子!
每个人的学习方式有所不同,有的喜欢看视频,有的喜欢看blog,有的喜欢看源码,但是根据常规顺序学一样知识的时候,最先看的应该是 官方文档 - LiveData 、官方文档 - ViewModel
我不太清楚别人是如何理解 LiveData、ViewModel
的,我也不知道这么理解对不对 ?
ViewModel 官网介绍
:ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。
ViewModel 自我理解
:保留数据、视图的意外丢失,支持Activity和依赖该Activity的Fragment共享数据源
LiveData 自我理解
:可被观察的数据持有类
ViewModel+LiveData 自我理解
生命周期的范围,一般都用到了Lifecycle
ViewModel
可分解为View、Model其主要作用是通过数据来驱动视图
LiveData特性,依托于采用的观察者模式
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<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<List<User>>();
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<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> 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;
/**
* @author MrLiu
* @date 2021/12/21
* desc
*/
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 就好~
实现方式 1:根据官方示例 获取ViewModel时,返回的是LiveData,导致只能通过类内方法进行设值,
个人不建议这么使用,虽然实现了出口统一,但是使用起来有点麻烦;不过不能一棒子打死,根据自己场景选取实现方式吧~
package com.example.livedata;
import android.util.Log;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
/**
* @author MrLiu
* @date 2021/12/21
* desc 类似官方的实现方式
*/
public class TestViewModel extends ViewModel {
private MutableLiveData<TestModel> liveData;
public LiveData<TestModel> getTestViewModel() {
if (liveData == null) {
liveData = new MutableLiveData<TestModel>();
}
return liveData;
}
/**
* 修改数据源
*/
public void setTestViewModel(TestModel testModel) {
liveData.postValue(testModel);
}
/**
* 可写可不写,主要看需求,用于监听依赖组件的生命周期
* 由于屏幕旋转导致的Activity重建,该方法不会被调用;
* 只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源
*/
@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<TestModel>() {
@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;
/**
* @author MrLiu
* @date 2021/12/21
* desc 只更改获取ViewModel的返回类型
*/
public class TestViewModel extends ViewModel {
private MutableLiveData<TestModel> mutableLiveData;
public MutableLiveData<TestModel> getTestViewModel_Mutable() {
if (mutableLiveData == null) {
mutableLiveData = new MutableLiveData<TestModel>();
}
return mutableLiveData;
}
/**
* 由于屏幕旋转导致的Activity重建,该方法不会被调用
* 只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源
*/
@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<TestModel>() {
@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;
/**
* @author MrLiu
* @date 2021/12/21
* desc
*/
public class TestViewModel extends ViewModel {
private MutableLiveData<String> stringMutableLiveData;
MutableLiveData<String> getAlone() {
if (stringMutableLiveData == null) {
stringMutableLiveData = new MutableLiveData<>();
}
return stringMutableLiveData;
}
/**
* 由于屏幕旋转导致的Activity重建,该方法不会被调用
* 只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源
*/
@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<String>() {
@Override
public void onChanged(String data) {
mAlone.setText(data);
}
});
//发送源,改变数据的地方,此处只是示例而已
mAlone.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
testViewModel.getAlone().postValue("小小笑话可笑可笑");
}
});
}
}
TestModel
package com.example.livedata;
/**
* @author MrLiu
* @date 2021/12/21
* desc
*/
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;
/**
* @author MrLiu
* @date 2021/12/21
* desc
*/
public class TestViewModel extends ViewModel {
private MutableLiveData<TestModel> liveData;
private MutableLiveData<TestModel> mutableLiveData;
private MutableLiveData<String> stringMutableLiveData;
public LiveData<TestModel> getTestViewModel() {
if (liveData == null) {
liveData = new MutableLiveData<TestModel>();
}
return liveData;
}
public MutableLiveData<TestModel> getTestViewModel_Mutable() {
if (mutableLiveData == null) {
mutableLiveData = new MutableLiveData<TestModel>();
}
return mutableLiveData;
}
public void setTestViewModel(TestModel testModel) {
liveData.postValue(testModel);
}
MutableLiveData<String> getAlone() {
if (stringMutableLiveData == null) {
stringMutableLiveData = new MutableLiveData<>();
}
return stringMutableLiveData;
}
/**
* 由于屏幕旋转导致的Activity重建,该方法不会被调用
* 只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源
*/
@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<TestModel>() {
@Override
public void onChanged(TestModel testModel) {
mTest.setText("姓名:" + testModel.getName() + " - 年龄:" + testModel.age);
}
});
testViewModel.getAlone().observe(this, new Observer<String>() {
@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("小小笑话可笑可笑");
}
});
}
}
前俩年有幸重新搭过一次项目框架,当时的
MVVM框架
采用的就是JetPack
内的组件
这里记录一份我在项目中使用 ViewVodel
+ LiveData
的伪代码