Android Jetpack中DataBinding将布局视图绑定到架构组件
Posted yu-Knight
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Jetpack中DataBinding将布局视图绑定到架构组件相关的知识,希望对你有一定的参考价值。
android Jetpack中DataBinding将布局视图绑定到架构组件(七)
将布局视图绑定到架构组件
AndroidX 库包含架构组件 (Architecture Components),可用于设计可靠、可测试且可维护的应用。数据绑定库 (Data Binding Library) 可与架构组件无缝协作,进一步简化界面的开发。应用中的布局可以绑定到架构组件中的数据,这些组件已经可帮助您管理界面控制器生命周期并通知数据变化。
本页介绍了如何将架构组件整合到您的应用中,以进一步凸显使用数据绑定库的优势。
使用 LiveData 将数据变化通知给界面
您可以使用 LiveData 对象作为数据绑定来源,自动将数据变化通知给界面。如需详细了解此架构组件,请参阅 LiveData 概览。
与实现 Observable 的对象(例如可观察字段)不同,LiveData 对象了解订阅数据更改的观察器的生命周期。了解这一点有许多好处,具体说明请参阅使用 LiveData 的优势。在 Android Studio 版本 3.1 及更高版本中,您可以在数据绑定代码中将可观察字段替换为 LiveData 对象。
要将 LiveData 对象与绑定类一起使用,您需要指定生命周期所有者来定义 LiveData 对象的范围。以下示例在绑定类实例化后将 Activity 指定为生命周期所有者:
Kotlin
class ViewModelActivity : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
// Inflate view and obtain an instance of the binding class.
val binding: UserBinding = DataBindingUtil.setContentView(this, R.layout.user)
// Specify the current activity as the lifecycle owner.
binding.setLifecycleOwner(this)
Java
class ViewModelActivity extends AppCompatActivity
@Override
protected void onCreate(Bundle savedInstanceState)
// Inflate view and obtain an instance of the binding class.
UserBinding binding = DataBindingUtil.setContentView(this, R.layout.user);
// Specify the current activity as the lifecycle owner.
binding.setLifecycleOwner(this);
您可以根据使用 ViewModel 管理界面相关数据中所述,使用 ViewModel 组件来将数据绑定到布局。在 ViewModel 组件中,您可以使用 LiveData 对象转换数据或合并多个数据源。以下示例展示了如何在 ViewModel 中转换数据:
Kotlin
class ScheduleViewModel : ViewModel()
val userName: LiveData
init
val result = Repository.userName
userName = Transformations.map(result) result -> result.value
Java
class ScheduleViewModel extends ViewModel
LiveData username;
public ScheduleViewModel()
String result = Repository.userName;
userName = Transformations.map(result, result -> result.value);
使用 ViewModel 管理界面相关数据
数据绑定库可与 ViewModel 组件无缝协作,这类组件会公开布局观察到并对其变化做出响应的数据。通过将 ViewModel 组件与数据绑定库结合使用,您可以将界面逻辑从布局移出,并移入到这些组件中,以便于测试。数据绑定库确保在需要时将视图与数据源绑定或解绑。大部分的其余工作是为了确保您公开的是正确的数据。有关此架构组件的更多信息,请参阅 ViewModel 概览。
要将 ViewModel 组件与数据绑定库一起使用,必须实例化从 ViewModel 类继承而来的组件,获取绑定类的实例,并将您的 ViewModel 组件分配给绑定类中的属性。以下示例展示了如何将组件与库结合使用:
Kotlin
class ViewModelActivity : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
// Obtain the ViewModel component.
val userModel: UserModel by viewModels()
// Inflate view and obtain an instance of the binding class.
val binding: UserBinding = DataBindingUtil.setContentView(this, R.layout.user)
// Assign the component to a property in the binding class.
binding.viewmodel = userModel
Java
class ViewModelActivity extends AppCompatActivity
@Override
protected void onCreate(Bundle savedInstanceState)
// Obtain the ViewModel component.
UserModel userModel = new ViewModelProvider(this).get(UserModel.class);
// Inflate view and obtain an instance of the binding class.
UserBinding binding = DataBindingUtil.setContentView(this, R.layout.user);
// Assign the component to a property in the binding class.
binding.viewmodel = userModel;
在您的布局中,使用绑定表达式将 ViewModel 组件的属性和方法分配给对应的视图,如以下示例所示:
<CheckBox
android:id="@+id/rememberMeCheckBox"
android:checked="@viewmodel.rememberMe"
android:onCheckedChanged="@() -> viewmodel.rememberMeChanged()" />
使用 Observable ViewModel 更好地控制绑定适配器
您可以使用实现 Observable 的 ViewModel 组件,向其他应用组件发出数据变化通知,这与使用 LiveData 对象的方式类似。
在某些情况下,您可能更愿意使用实现 Observable 接口的 ViewModel 组件,而不是使用 LiveData 对象,即使这样会失去对 LiveData 的生命周期管理功能也不影响。使用实现 Observable 的 ViewModel 组件可让您更好地控制应用中的绑定适配器。例如,这种模式可让您更好地控制数据更改时发出的通知,您还可以指定自定义方法来设置双向数据绑定中的属性值。
如需实现可观察的 ViewModel 组件,您必须创建一个从 ViewModel 类继承而来并实现 Observable 接口的类。您可以使用 addOnPropertyChangedCallback() 和 removeOnPropertyChangedCallback() 方法提供观察器订阅或取消订阅通知时的自定义逻辑。您还可以在 notifyPropertyChanged() 方法中提供属性更改时运行的自定义逻辑。以下代码示例展示了如何实现一个可观察的 ViewModel:
Kotlin
/**
* A ViewModel that is also an Observable,
* to be used with the Data Binding Library.
*/
open class ObservableViewModel : ViewModel(), Observable
private val callbacks: PropertyChangeRegistry = PropertyChangeRegistry()
override fun addOnPropertyChangedCallback(
callback: Observable.OnPropertyChangedCallback)
callbacks.add(callback)
override fun removeOnPropertyChangedCallback(
callback: Observable.OnPropertyChangedCallback)
callbacks.remove(callback)
/**
* Notifies observers that all properties of this instance have changed.
*/
fun notifyChange()
callbacks.notifyCallbacks(this, 0, null)
/**
* Notifies observers that a specific property has changed. The getter for the
* property that changes should be marked with the @Bindable annotation to
* generate a field in the BR class to be used as the fieldId parameter.
*
* @param fieldId The generated BR id for the Bindable field.
*/
fun notifyPropertyChanged(fieldId: Int)
callbacks.notifyCallbacks(this, fieldId, null)
Java
/**
* A ViewModel that is also an Observable,
* to be used with the Data Binding Library.
*/
class ObservableViewModel extends ViewModel implements Observable
private PropertyChangeRegistry callbacks = new PropertyChangeRegistry();
@Override
protected void addOnPropertyChangedCallback(
Observable.OnPropertyChangedCallback callback)
callbacks.add(callback);
@Override
protected void removeOnPropertyChangedCallback(
Observable.OnPropertyChangedCallback callback)
callbacks.remove(callback);
/**
* Notifies observers that all properties of this instance have changed.
*/
void notifyChange()
callbacks.notifyCallbacks(this, 0, null);
/**
* Notifies observers that a specific property has changed. The getter for the
* property that changes should be marked with the @Bindable annotation to
* generate a field in the BR class to be used as the fieldId parameter.
*
* @param fieldId The generated BR id for the Bindable field.
*/
void notifyPropertyChanged(int fieldId)
callbacks.notifyCallbacks(this, fieldId, null);
Android中jetpack讲解(详)--课外拓展知识讲解
Android中jetpack讲解(详)
说明:本篇文章是在一次课堂上,我为班级同学分享的一篇关于Android最新的jetpack的普及知识,内容广泛,仅仅是了解性的内容,如果需要深入了解,本篇文章可能不适合。
Butter Knife(黄刀油)
介绍
用于Android视图的字段和方法绑定,它使用注释处理为您生成样板代码。
- 消去代码中通过findviewById方法来找控件。
- 可以简化事件点击的处理
``
TextView textView = findViewById(R.id.textView);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
``
@BindView(R.id.button)
Button button;
@BindView(R.id.normaltext)
TextView normaltext;
@OnClick(R.id.button)
public void onViewClicked() {
}
用法
1.支持jdk1.8
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
2.添加butterknife依赖
dependencies {
implementation 'com.jakewharton:butterknife:10.2.3'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3'
}
3.安装butterknife插件
在Android studio插件中安装Butter Knife
4.具体使用步骤
右边布局,找到Generate
注意:如果想要一键生成点击事件或者想要获取控件,一定要让各个控件有id才行,否则会出现下面错误。
Jetpack
Jetpack中的有些组件并不是第一次推出,其中LifeCycle、LiveData、ViewModel、Room等组件早在 Google I/O 2017年大会上就随着 Android Architecture Component(AAC)一起推出了,但是推广效果一般。时隔一年后谷歌在AAC的基础之上发布了Jetpack,并发布了其他工具以解决Android技术选型乱以及开发不规范等问题。
Jetpack的内容
定义
Jetpack 是一个由多个库组成的套件,可帮助开发者遵循最佳做法,减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者精力集中编写重要的代码。
为什么要用Jetpack
Jetpack包含的内容
- Data Binding:数据绑定库是一种支持库,借助该库,您可以使用声明性格式(而非程序化地)将布局中的界面组件绑定到应用中的数据源。(类似于Butter Knife)
2. LiveData:同RxJava的作用一样,对数据进行监听,优点就是无需处理生命周期、无内存泄漏等。(使用到了观察者模式,监听数据的改变,数据一变,就会通过回调自动刷新相应UI)
MutableLiveData:这个数据类有着监听自身变化的能力,并且通过监听者模式告诉 其他组件数据更新。
3.ViewModel:当做MVVM的ViewModel层,并具有声明周期意识的处理和UI相关的数据。
它会在活动重建时仍然保存数据,在活动创建完成后从中获取数据
(简化了应用中目标之间导航的实现)
Jetpack中的Room数据库
详细教程
https://developer.android.google.cn/training/data-storage/room
Room包含的三大注解
-
Database:包含数据库持有者,并作为与 App 持久关联数据的底层连接的主要访问点。
用 @Database 注解的类应满足以下条件:
是一个继承至 RoomDatabase 的抽象类。
在注解中包含与数据库相关联的实体列表。
包含一个具有 0 个参数的抽象方法,并返回用 @Dao 注解的类。
在运行时,您可以通过调用 Room.databaseBuilder() 或 Room.inMemoryDatabaseBuilder() 获取 Database 实例。 -
Entity:表示数据库的表
-
Dao:包含用于访问数据库的方法。
Room数据库如何使用
引入依赖
//Room
def room_version = “2.2.5”
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
// optional - RxJava support for Room
implementation "androidx.room:room-rxjava2:$room_version"
// optional - Guava support for Room, including Optional and ListenableFuture
implementation "androidx.room:room-guava:$room_version"
// optional - Test helpers
testImplementation "androidx.room:room-testing:$room_version"
Room实现四步曲
- 编写Entity层
- 编写Dao层(访问数据库的接口)
- 编写Database层(类似于Manager)
4.编写MainActivity中访问数据库的具体实现
编写Entity
package com.example.androidroom;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity
public class Goods {
//主键,默认自增
@PrimaryKey(autoGenerate =true)
int id;
//修改列名
// @ColumnInfo(name = "first_name")
double price;
String content;
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Goods(int id, double price, String content,String name) {
this.id = id;
this.price = price;
this.content = content;
this.name = name;
}
@Override
public String toString() {
return "Goods{" +
"id=" + id +
", price=" + price +
", content='" + content + '\\'' +
", name='" + name + '\\'' +
'}';
}
}
编写Dao层
注:Goods …goods中的三个点代表可以传入多个参数
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;
import java.util.List;
@Dao
public interface GoodsDao {
//查询所有商品
@Query("SELECT * FROM Goods")
List<Goods> getAllGoods();
//删除
// @Delete
@Query("delete from goods")
void deleteGoods();
//修改
@Update
void updateGoods(Goods ...goods);
//增加
@Insert
void insertGoods(Goods ...goods);
}
Database
注意事项:
- 使用Database需要注意指明entities(表),version版本(如果你在entity增加了属性,就需要改变版本),exportSchema默认为false
- 使用Database时,需要让其为抽象类,同时Dao层方法也需要为抽象类
- 其次,需要继承RoomDatabase
import androidx.room.RoomDatabase;
@Database(entities = Goods.class,version = 1,exportSchema = false)
public abstract class GoodsDateBase extends RoomDatabase {
public abstract GoodsDao getGoodsDao();
}
####MainActivity获取数据库层
注意:
allowMainThreadQueries()这个必须有,如果无的话,会报线程异常, Room 不支持在主线程上进行数据库访问,因为它可能会长时间锁定 UI。不过异步查询(返回 LiveData 或 Flowable 实例的查询)不受此规则约束,因为它们在需要时会在后台线程进行异步查询。
/**
* 获取数据库
*/
private void getData() {
goodsDateBase= Room.databaseBuilder(RoomActivity.this,GoodsDateBase.class,"Good_database").allowMainThreadQueries().build();
goodsDao=goodsDateBase.getGoodsDao();
}
时间锁定 UI。不过异步查询(返回 LiveData 或 Flowable 实例的查询)不受此规则约束,因为它们在需要时会在后台线程进行异步查询。
/**
* 获取数据库
*/
private void getData() {
goodsDateBase= Room.databaseBuilder(RoomActivity.this,GoodsDateBase.class,"Good_database").allowMainThreadQueries().build();
goodsDao=goodsDateBase.getGoodsDao();
}
后续
后续我会在明年的暑假进行进一步详细的去学习jetpack相关组件,期待后面的精彩详细文章的产出
以上是关于Android Jetpack中DataBinding将布局视图绑定到架构组件的主要内容,如果未能解决你的问题,请参考以下文章
Android高级Jetpack架构组件+Jetpack compose强化实战
Android Jetpack 是不是需要使用 Kotlin 语言?
Android Jetpack Navigation:如何在 OnNavigatedListener 中获取目的地的片段实例?