Jetpack 是一个由多个库组成的套件,可帮助开发者遵循最佳作法,减小样板代码并编写可在各类 Android 版本和设备中一致运行的代码,让开发者精力集中编写重要的代码。java
Android Architecture Component (AAC)。android
请注意,每一个组件仅依赖于其下一级的组件。例如,Activity 和 Fragment 仅依赖于视图模型。存储区是惟一依赖于其余多个类的类;在本例中,存储区依赖于持久性数据模型和远程后端数据源。后端
ViewModel应该能够算是JetPack组建中最重要的组件之一。架构
ViewModel是专门用于存放与界面相关的数据。app
ViewModel的生命周期贯穿于Activity整个生命周期,只有Activity销毁时,ViewModel才会销毁。ide
implementation 'androidx.fragment:fragment-ktx:1.3.0-beta01' implementation 'androidx.activity:activity-ktx:1.2.0-beta01' implementation 'androidx.lifecycle:lifecycle-viewmodel:2.3.0-beta01' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0-beta01'
class ViewModelOne : ViewModel() {}
val viewModelOne by ViewModelLazy<ViewModelOne>(ViewModelOne::class, { viewModelStore }, { defaultViewModelProviderFactory })
val viewModelOnes by viewModels<ViewModelOne> { defaultViewModelProviderFactory }
非懒加载模式必需要等Activity 在OnCreate后才能初始化,不然运行报错。函数
val viewModelPro = ViewModelProvider( viewModelStore, defaultViewModelProviderFactory ).get(ViewModelOne::class.java)
onClear回调函数处理资源回收closeWithRuntimeException布局
ViewModel绝对不能引用View、Lifecycle或任何可能包含对Activity上下文的引用的类gradle
class VmFactory(private val count: Int) : ViewModelProvider.Factory { override fun <T : ViewModel?> create(modelClass: Class<T>): T { if (modelClass.isAssignableFrom(ViewModelOne::class.java)) { return ViewModelOne() as T } else if (modelClass.isAssignableFrom(ViewModelTwo::class.java)) { return ViewModelTwo(count) as T } else { throw ClassNotFoundException("class $modelClass ViewModel没有注册到工厂类") } } }
ViewModelActivityui
class ViewModelActivity : AppCompatActivity() { val TAG = this.javaClass.simpleName val viewModelOne by ViewModelLazy<ViewModelOne>(ViewModelOne::class, { viewModelStore }, { defaultViewModelProviderFactory }) val viewModelOnes by viewModels<ViewModelOne> { defaultViewModelProviderFactory } //android view model val viewModelTwo by viewModels<ViewModelTwo> { VmFactory(10) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_view_model) val viewModelPro = ViewModelProvider( viewModelStore, defaultViewModelProviderFactory ).get(ViewModelOne::class.java) Log.d(TAG, "viewModelOne ${viewModelOne.getNow()}") Log.d(TAG, "viewModelOnes ${viewModelOnes.getNow()}") Log.d(TAG, "viewModelPro ${viewModelPro.getNow()}") Log.d(TAG, "viewModelTwo ${viewModelTwo.getNow()}") btn_again.setOnClickListener { startActivity(Intent(this, ViewModelActivity::class.java)) } } }
ViewModelKt
class ViewModelOne : ViewModel() { val TAG = this.javaClass.simpleName var counter = 0 init { Log.d(TAG, "ViewModelOne建立") } fun getNow(): String { return "ViewModelOne: ${System.currentTimeMillis()}" } override fun onCleared() { super.onCleared() Log.d(TAG, "ViewModelOne销毁") } } class ViewModelTwo(count: Int) : ViewModel() { val TAG = this.javaClass.simpleName var counter = 0 init { Log.d(TAG, "ViewModelTwo建立") counter = count } fun getNow(): String { return "ViewModelTwo: ${System.currentTimeMillis()} ${this.counter}" } override fun onCleared() { super.onCleared() Log.d(TAG, "ViewModelTwo销毁") } }
VmFactory
class VmFactory(private val count: Int) : ViewModelProvider.Factory { override fun <T : ViewModel?> create(modelClass: Class<T>): T { if (modelClass.isAssignableFrom(ViewModelOne::class.java)) { return ViewModelOne() as T } else if (modelClass.isAssignableFrom(ViewModelTwo::class.java)) { return ViewModelTwo(count) as T } else { throw ClassNotFoundException("class $modelClass ViewModel没有注册到工厂类") } } }
ViewModel.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/btn_again" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="启动界面" /> </LinearLayout> </LinearLayout>
//在module的build.gradle中 apply plugin: 'kotlin-kapt'//必须 android{ //AS 4.0 如下, dataBinding{ enabled true } //AS 4.1以后 bindingFeature{ dataBinding = true // for view binding : // viewBinding = true } }
<layout> <data class=""> </data> <!-- 原有的UI的xml布局放在layout标签内便可。data标签内存放用于xml的数据变量,类型 --> <LinearLayout> </LinearLayout> </layout>
val binding = DataBindingUtil.setContentView<ActivityDataBindingBinding>( this, R.layout.activity_data_binding )
variable声明变量;import导入类型;对于xml的特殊符号须要转义相似&
绑定xml与data格式:@{}、@={}(双向绑定)
??判空
?:三目运算符
@string/str_name资源引用,可用占位符format
+拼接字符,使用**``**反引号
default设置默认值
include绑定
点击事件
implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha06'
<androidx.recyclerview.widget.RecyclerView app:adapter="@{adapter}" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" tools:itemCount="5" tools:listitem="@layout/item_data_binding" />
@BindingConversion
若是属性不能匹配类型参数将自动根据类型参数匹配到该注解修饰的方法来转换
@BindingConversion fun str2Color(str: String): Drawable { return when (str) { "red" -> { ColorDrawable(Color.RED) } "blue" -> ColorDrawable(Color.BLUE) else -> { ColorDrawable(Color.YELLOW) } } }
@BindingAdapter
设置自定义属性. 能够覆盖系统原有属性
@BindingAdapter("android:textColor", requireAll = false) fun getColor(view: TextView, type: Int) { val color = when (type) { 0 -> R.color.colorAccent 1 -> R.color.colorPrimaryDark 2 -> android.R.color.holo_red_dark 3 -> android.R.color.holo_orange_dark else -> R.color.colorPrimary } view.setTextColor(view.context.resources.getColor(color)) }
@Bindable
设置数据刷新视图. 自动生成BR的ID
注解才会自动在build目录BR类中生成entry, 要求方法名必须以get开头
DatabindingActivity
class DataBindingActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding = DataBindingUtil.setContentView<ActivityDataBindingBinding>( this, R.layout.activity_data_binding ) binding.apply { name = null address = "TianJin 天津" observeName = ObservableField("observeName") user = User() observeUser = ObserveUser() observeFieldUser = ObserveFieldUser() btnChange.setOnClickListener { name = "姚鑫" address = null user?.name = "孙悟空" observeUser?.age = 18 observeUser?.name = "张曼玉" observeFieldUser?.name?.set("林志玲") } adapter = DataBindingAdapter() info = ItemBean(2,"Activity Item") } } }
DatabindingActivity.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="name"
type="String" />
<variable
name="address"
type="String" />
<variable
name="observeName"
type="androidx.databinding.ObservableField<String>" />
<variable
name="user"
type="com.yx.androidseniorpreparetest.fifth.User" />
<variable
name="observeUser"
type="com.yx.androidseniorpreparetest.fifth.ObserveUser" />
<variable
name="observeFieldUser"
type="com.yx.androidseniorpreparetest.fifth.ObserveFieldUser" />
<variable
name="adapter"
type="androidx.recyclerview.widget.RecyclerView.Adapter" />
<variable
name="info"
type="com.yx.androidseniorpreparetest.fifth.ItemBean" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="演示DataBinding"
android:textColor="#000000"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@{name}"
android:textColor="#000000"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@{name??`Null Name`}"
android:textColor="#000000"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@{address,default=`tianjin`}"
android:textColor="#000000"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@{name==null?`null`:`nonull`}"
android:textColor="#000000"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@{@string/str_name(name)}"
android:textColor="#000000"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@{observeName}"
android:textColor="#000000"
android:textSize="20sp" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@={observeName}"
android:textColor="#000000"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@={user.name}"
android:textColor="#000000"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@{observeUser.name + observeUser.age}"
android:textColor="#000000"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@={observeUser.age+``}"
android:textColor="#000000"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@={observeFieldUser.name}"
android:textColor="#000000"
android:textSize="20sp" />
<Button
android:id="@+id/btn_change"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@{`pink`}"
android:gravity="center"
android:text="改变值"
android:textColor="#000000"
android:textSize="20sp" />
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:adapter="@{adapter}"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="5"
tools:listitem="@layout/item_data_binding" />
<include
info="@{info}"
layout="@layout/item_data_binding" />
</LinearLayout>
</layout>
user
class User { var name = "姚鑫" var age = 30 var desc = "DataBinding真好用!" } class ObserveUser : BaseObservable() { var age = 31 var name = "" set(value) { notifyPropertyChanged(BR.name) field = value + "yao" } @Bindable get() { return "$field 姚鑫Name" } var desc = "这里是ObserveUser描述" set(value) { notifyPropertyChanged(BR.desc) field = value + "xin" } @Bindable get() { return "$field 姚鑫Desc" } var str = "" set(value) { field = value notifyPropertyChanged(BR.str) } @Bindable get() { return "age $age name $name desc $desc" } } class ObserveFieldUser { var name = ObservableField("姚鑫") var age = ObservableInt(30) var desc = ObservableField("DataBinding真好用!") var str = "age $age name $name desc $desc" }
ItemBean
data class ItemBean(val type: Int, val text: String)
DataBindingAdapter
class DataBindingAdapter : RecyclerView.Adapter<DataBindingAdapter.DataBindingViewHolder>() { private val mList = mutableListOf<ItemBean>() init { for (i in 0..5) { mList.add(ItemBean(i, "明细 $i")) } } class DataBindingViewHolder(private val binding: ItemDataBindingBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(bean: ItemBean) { binding.info = bean binding.executePendingBindings() } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DataBindingViewHolder { return DataBindingViewHolder( ItemDataBindingBinding.inflate( LayoutInflater.from(parent.context), parent, false ) ) } override fun onBindViewHolder(holder: DataBindingViewHolder, position: Int) { holder.bind(mList[position]) } override fun getItemCount(): Int = mList.size }
ItemDataBinding.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <data> <import type="com.yx.androidseniorpreparetest.fifth.DataBindingUtilsKt" /> <variable name="info" type="com.yx.androidseniorpreparetest.fifth.ItemBean" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="@{DataBindingUtilsKt.getTitle(info.text)}" android:textColor="@{info.type}" android:textSize="20sp" tools:text="content" /> </LinearLayout> </layout>
DataBindingUtils
@BindingConversion fun str2Color(str: String): Drawable { return when (str) { "red" -> { ColorDrawable(Color.RED) } "blue" -> ColorDrawable(Color.BLUE) else -> { ColorDrawable(Color.YELLOW) } } } fun getTitle(type: String): String { return "type:$type" } @BindingAdapter("android:textColor", requireAll = false) fun getColor(view: TextView, type: Int) { val color = when (type) { 0 -> R.color.colorAccent 1 -> R.color.colorPrimaryDark 2 -> android.R.color.holo_red_dark 3 -> android.R.color.holo_orange_dark else -> R.color.colorPrimary } view.setTextColor(view.context.resources.getColor(color)) }
项目代码