Android--Jetpack的使用(一)
3、ViewModel + LiveData + dataBinding
4、ViewModel + SavedStateHandle + LiveData + dataBinding
1、ViewModel
ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存
例子:
代码:
MyVModel
import androidx.lifecycle.ViewModel;
public class MyVModel extends ViewModel {
public int num=0;
}
MainActivity
//创建MyVModel
myVModel = AndroidViewModelFactory.getInstance(getApplication()).create(MyVModel.class);
//+1
myVModel.num++;
tv.setText(String.valueOf(myVModel.num));
//+2
myVModel.num += 2;
tv.setText(String.valueOf(myVModel.num));
2、ViewModel + LiveData
LiveData是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
例子:
代码:
MyVModelWithLiveData
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class MyVModelWithLiveData extends ViewModel {
//创建LiveData对象
private MutableLiveData<Integer> data;
//创建get方法
public MutableLiveData<Integer> getNum() {
//当第一次get的时候初始化
if (null == data) {
data = new MutableLiveData<>();
data.setValue(0);
}
return data;
}
//方法
public void addNum(int a) {
data.setValue(data.getValue() + a);
}
}
MainActivity
//创建viewmodel
myVModelWithLiveData = AndroidViewModelFactory.getInstance(getApplication()).create(MyVModelWithLiveData.class);
//观察LiveData对象
myVModelWithLiveData.getNum().observe(this, new Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
//当监听到数据发生变化时跟新界面
tv1.setText(String.valueOf(integer ));
}
});
3、ViewModel+LiveData+dataBinding
在原来的方法中,就是通过findviewById()
的方法拿到TextView
,然后通过setText
方法把viewmodel
中的number
跟TextView
绑定到一块.
在使用了dataBinding以后,就可以使用赋值表达式@{}
来实现绑定,如下:
<TextView
android:text="@{String.valueOf(vmodel.number),default=0}" />
例子
代码
module的build.gradle
android {
...
/*配置使用dataBinding*/
buildFeatures {
dataBinding true;
}
/*配置使用jdk1.8,因为会用到Lambda表达式*/
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
MyViewModel
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel {
private MutableLiveData<Integer> number;
//控制显隐
private MutableLiveData<Boolean> isVisibiliy;
public MutableLiveData<Integer> getNumber() {
if (null == number) {
number = new MutableLiveData<>();
number.setValue(0);
}
return number;
}
public MutableLiveData<Boolean> getIsVisibiliy() {
if (isVisibiliy == null) {
isVisibiliy = new MutableLiveData<>();
isVisibiliy.setValue(true);
}
return isVisibiliy;
}
public void setIsVisibiliy() {
isVisibiliy.setValue(!isVisibiliy.getValue());
}
public void addNum(int num) {
number.setValue(number.getValue() + num);
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<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>
<!--导入View类-->
<import type="android.view.View" />
<variable
name="vmodel"
type="com.example.d0810.MyViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
tools:context=".MainActivity2">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@{String.valueOf(vmodel.number),default=0}"
android:textSize="30sp" />
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{()->vmodel.addNum(1)}"
android:text="+1" />
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{()->vmodel.addNum(2)}"
android:text="+2" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:background="#000" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_v"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="文本"
android:textSize="28sp"
android:visibility="@{vmodel.isVisibiliy ? View.VISIBLE : View.INVISIBLE}" />
<Button
android:id="@+id/btn_v"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:onClick="@{() -> vmodel.setIsVisibiliy()}"
android:text="控制显隐" />
</LinearLayout>
</LinearLayout>
</layout>
MainActivity2
public class MainActivity2 extends AppCompatActivity {
private ActivityMain2Binding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyViewModel myViewModel = AndroidViewModelFactory.getInstance(getApplication()).create(MyViewModel.class);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main2);
binding.setVmodel(myViewModel);
//
binding.setLifecycleOwner(this);
}
}
4、ViewModel的SavedStateHandle
当程序推出到后台的时候,然后被手机系统回收导致的进程终止,在原来的方式是使用 onSaveInstanceState()
方法来进行保存数据和状态。
所以在 ViewModel
的构造函数的时候会接收一个 SavedStateHandle
对象,这是一个键值对映射,用户保存状态。
注意: 状态必须是简单的轻量级状态。对于复杂或大型数据,您应该使用本地持久性存储。
SavedStateHandle所有的方法
- get(String key) :根据键值来获取数组
- contains(String key):判断handle中是否包含key这个键
- remove(String key):根据键值删除数据
- set(String key, T value):保存数据
- keys():获取所有的键值
- getLiveData(String key):返回封装在
LiveData
可观察对象中的值。
例子效果图
SavedStateHandle的使用
ScoreVmodel
public class ScoreVmodel extends ViewModel {
public final String ASCORE = "aScore";
public final String BSCORE = "bScore";
public final String AUNDOSCORE = "aUndoScore";
public final String BUNDOSCORE = "bUndoScore";
//保存状态模块
private SavedStateHandle handle;
public ScoreVmodel(SavedStateHandle handle) {
this.handle = handle;
}
//获取A队的分数
public MutableLiveData<Integer> getaScore() {
if (!handle.contains(ASCORE)) {
handle.set(ASCORE, 0);
}
return handle.getLiveData(ASCORE);
}
//获取B队的分数
public MutableLiveData<Integer> getbScore() {
if (!handle.contains(BSCORE)) {
handle.set(BSCORE, 0);
}
return handle.getLiveData(BSCORE);
}
//添加A队的分数
public void addAScore(int s) {
//首先把A队和B队的分数保存起来
handle.set(AUNDOSCORE, getaScore().getValue());
handle.set(BUNDOSCORE, getbScore().getValue());
getaScore().setValue(getaScore().getValue() + s);
}
//添加B队的分数
public void addBScore(int s) {
//首先把A队和B队的分数保存起来
handle.set(AUNDOSCORE, getaScore().getValue());
handle.set(BUNDOSCORE, getbScore().getValue());
//再计算分数
getbScore().setValue(getbScore().getValue() + s);
}
public void reset() {
//首先把A队和B队的分数保存起来
handle.set(AUNDOSCORE, getaScore().getValue());
handle.set(BUNDOSCORE, getbScore().getValue());
handle.set(ASCORE, 0);
handle.set(BSCORE, 0);
}
//撤回一次
public void undoScore() {
handle.set(ASCORE, handle.getLiveData(AUNDOSCORE).getValue());
handle.set(BSCORE, handle.getLiveData(BUNDOSCORE).getValue());
}
}
ScoreActivity
public class ScoreActivity extends AppCompatActivity {
private ActivityScoreBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_score);
ScoreVmodel vmodel = new ViewModelProvider(this, new SavedStateViewModelFactory(getApplication(), this)).get(ScoreVmodel.class);
binding.setModel(vmodel);
/**
* 这句话时必须要加上的,这个方法的注释如下
* Sets the {@link LifecycleOwner} that should be used for observing changes of
* LiveData in this binding. If a {@link LiveData} is in one of the binding expressions
* and no LifecycleOwner is set, the LiveData will not be observed and updates to it
* will not be propagated to the UI.
* 我理解的大概意思就是 这个方法就是把 LifecycleOwner 和 LiveData 绑定到一块,只有绑定到一块。当
* 数据发生变化的时候 才会更新UI界面
*/
binding.setLifecycleOwner(this);
}
}
XML布局文件
<?xml version="1.0" encoding="utf-8"?>
<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="model"
type="com.example.d0810.score.ScoreVmodel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".score.ScoreActivity">
<TextView
android:id="@+id/tv_ta"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/a"
android:textColor="@color/teamAColor"
android:textSize="@dimen/teamSizeText"
app:layout_constraintBottom_toTopOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline2" />
<TextView
android:id="@+id/tv_tb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/b"
android:textColor="@color/teamBColor"
android:textSize="@dimen/teamSizeText"
app:layout_constraintBottom_toTopOf="@+id/guideline2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toTopOf="@+id/guideline2" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.05" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.2" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.35" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.65" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.75" />
<TextView
android:id="@+id/tv_ascore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(model.getaScore()),default=@string/zero}"
android:textColor="@color/teamAColor"
android:textSize="@dimen/scoreTextSize"
app:layout_constraintBottom_toTopOf="@+id/guideline3"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline3" />
<TextView
android:id="@+id/tv_bscore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(model.getbScore()),default=@string/zero}"
android:textColor="@color/teamBColor"
android:textSize="@dimen/scoreTextSize"
app:layout_constraintBottom_toTopOf="@+id/guideline3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.504"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toTopOf="@+id/guideline3" />
<Button
android:id="@+id/btn_a1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/teamAColor"
android:onClick="@{() -> model.addAScore(1) }"
android:text="@string/add1"
android:textColor="@android:color/white"
android:textSize="30sp"
app:layout_constraintBottom_toTopOf="@+id/guideline4"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline4" />
<Button
android:id="@+id/btn_a2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/teamAColor"
android:onClick="@{() -> model.addAScore(2) }"
android:text="@string/add2"
android:textColor="@android:color/white"
android:textSize="@dimen/btnTextsize"
app:layout_constraintBottom_toTopOf="@+id/guideline5"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline5" />
<Button
android:id="@+id/btn_a3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/teamAColor"
android:onClick="@{() -> model.addAScore(3) }"
android:text="@string/add3"
android:textColor="@android:color/white"
android:textSize="@dimen/btnTextsize"
app:layout_constraintBottom_toTopOf="@+id/guideline6"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline6" />
<Button
android:id="@+id/btn_b3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/teamBColor"
android:onClick="@{() -> model.addBScore(3) }"
android:text="@string/add3"
android:textColor="@android:color/white"
android:textSize="@dimen/btnTextsize"
app:layout_constraintBottom_toTopOf="@+id/guideline6"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toTopOf="@+id/guideline6" />
<Button
android:id="@+id/btn_b2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/teamBColor"
android:onClick="@{() -> model.addBScore(2)}"
android:text="@string/add2"
android:textColor="@android:color/white"
android:textSize="@dimen/btnTextsize"
app:layout_constraintBottom_toTopOf="@+id/guideline5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toTopOf="@+id/guideline5" />
<Button
android:id="@+id/btn_b1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/teamBColor"
android:onClick="@{() -> model.addBScore(1) }"
android:text="@string/add1"
android:textColor="@android:color/white"
android:textSize="@dimen/btnTextsize"
app:layout_constraintBottom_toTopOf="@+id/guideline4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toTopOf="@+id/guideline4" />
<ImageButton
android:id="@+id/ibtn_undo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/undo"
android:onClick="@{() -> model.undoScore() }"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline7"
app:srcCompat="@drawable/ic_baseline_undo_24" />
<ImageButton
android:id="@+id/ibtn_reset"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/reset"
android:onClick="@{() -> model.reset()}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toTopOf="@+id/guideline7"
app:srcCompat="@drawable/ic_baseline_loop_24" />
<View
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="2dp"
android:layout_marginBottom="5dp"
android:background="@android:color/darker_gray"
app:layout_constraintBottom_toTopOf="@+id/guideline7"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
5、例子下载
https://download.csdn.net/download/ljp345775/12702818
参考文献
[1] Android开发教程(2019最新版,使用JetPack)
[2] Android官方的开发文档
本文地址:https://blog.csdn.net/ljp345775/article/details/107925929
上一篇: idea手动刷新git分支
下一篇: 安卓DeepLink方法拉起App页面
推荐阅读
-
在c#中使用servicestackredis操作redis的实例代码
-
如何开启IE10浏览器快速导航功能一键选择打开的网页
-
HighCharts图表控件在ASP.NET WebForm中的使用总结(全)
-
sqlserver中delete、update中使用表别名和oracle的区别
-
Sql学习第三天——SQL 关于CTE(公用表达式)的递归查询使用
-
使用vue点击li,获取当前点击li父辈元素的属性值方法
-
详解使用DotNet CLI创建自定义的WPF项目模板
-
sql server 还原数据库时提示数据库正在使用,无法进行操作的解决方法
-
MySQL一个索引最多有多少个列?真实的测试例子
-
使用mysql中遇到的几个问题