Skip to content

Commit

Permalink
feat: #286 使用getBinding()获取ViewBinding实例
Browse files Browse the repository at this point in the history
  • Loading branch information
liangjingkanji committed Nov 11, 2022
1 parent 22b75b0 commit 4501f09
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 29 deletions.
53 changes: 39 additions & 14 deletions brv/src/main/java/com/drake/brv/BindingAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.NO_ID
import androidx.viewbinding.ViewBinding
import com.drake.brv.animation.*
import com.drake.brv.annotaion.AnimationType
import com.drake.brv.item.*
import com.drake.brv.listener.*
import com.drake.brv.utils.BRV
import com.drake.brv.utils.setDifferModels
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Modifier
import java.util.concurrent.*
import kotlin.math.min
Expand Down Expand Up @@ -153,13 +155,13 @@ open class BindingAdapter : RecyclerView.Adapter<BindingAdapter.BindingViewHolde

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingViewHolder {
val vh = if (dataBindingEnable) {
val viewDataBinding = DataBindingUtil.inflate<ViewDataBinding>(
val viewBinding = DataBindingUtil.inflate<ViewDataBinding>(
LayoutInflater.from(parent.context), viewType, parent, false
)
if (viewDataBinding == null) {
if (viewBinding == null) {
BindingViewHolder(parent.getView(viewType))
} else BindingViewHolder(
viewDataBinding
viewBinding
)
} else {
BindingViewHolder(parent.getView(viewType))
Expand Down Expand Up @@ -1088,12 +1090,13 @@ open class BindingAdapter : RecyclerView.Adapter<BindingAdapter.BindingViewHolde
val adapter: BindingAdapter = this@BindingAdapter
val modelPosition get() = layoutPosition - headerCount

private var viewDataBinding: ViewDataBinding? = null
@PublishedApi
internal var viewBinding: ViewBinding? = null

constructor(itemView: View) : super(itemView)

constructor(viewDataBinding: ViewDataBinding) : super(viewDataBinding.root) {
this.viewDataBinding = viewDataBinding
constructor(viewBinding: ViewDataBinding) : super(viewBinding.root) {
this.viewBinding = viewBinding
}

init {
Expand Down Expand Up @@ -1136,11 +1139,13 @@ open class BindingAdapter : RecyclerView.Adapter<BindingAdapter.BindingViewHolde
onBind?.invoke(this@BindingViewHolder)

val dataBindingEnable = dataBindingEnable
val viewDataBinding = viewDataBinding
if (dataBindingEnable && viewDataBinding != null) {
val viewBinding = viewBinding
if (dataBindingEnable && viewBinding != null) {
try {
viewDataBinding.setVariable(modelId, model)
viewDataBinding.executePendingBindings()
if (viewBinding is ViewDataBinding) {
viewBinding.setVariable(modelId, model)
viewBinding.executePendingBindings()
}
} catch (e: Exception) {
val message = "DataBinding type mismatch ...(${context.resources.getResourceEntryName(itemViewType)}.xml:1)"
Log.e(javaClass.simpleName, message, e)
Expand All @@ -1150,14 +1155,34 @@ open class BindingAdapter : RecyclerView.Adapter<BindingAdapter.BindingViewHolde


/**
* 返回匹配泛型的数据绑定对象ViewDataBinding
* 返回匹配泛型的数据绑定对象[ViewBinding]
*/
fun <B : ViewDataBinding> getBinding(): B = viewDataBinding as B
inline fun <reified B : ViewBinding> getBinding(): B {
if (viewBinding == null) {
val method = B::class.java.getMethod("bind", View::class.java)
val viewBinding = method.invoke(null, itemView) as B
this.viewBinding = viewBinding
return viewBinding
}
return viewBinding as B
}

/**
* 返回匹配泛型的数据绑定对象ViewDataBinding, 如果不匹配则返回null
* 返回匹配泛型的数据绑定对象[ViewBinding], 如果不匹配则返回null
*/
fun <B : ViewDataBinding> getBindingOrNull(): B? = viewDataBinding as? B
inline fun <reified B : ViewBinding> getBindingOrNull(): B? {
if (viewBinding == null) {
return try {
val method = B::class.java.getMethod("bind", View::class.java)
val viewBinding = method.invoke(null, itemView) as? B
this.viewBinding = viewBinding
viewBinding
} catch (e: InvocationTargetException) {
null
}
}
return viewBinding as? B
}

/**
* 查找ItemView上的视图
Expand Down
38 changes: 24 additions & 14 deletions docs/view-binding.md
Original file line number Diff line number Diff line change
@@ -1,47 +1,55 @@
假设你不想使用DataBinding只想用ViewBinding可以阅读以下内容
假设不想使用DataBinding只想用ViewBinding可以阅读以下内容

> 其实使用ViewBinding和DataBinding的查找视图对象用法一致, 都是调用`getBinding()`
## 前言

我推荐使用DataBinding而非ViewBinding, 理由如下
更推荐使用DataBinding而非ViewBinding, 理由如下

1. 首先MVVM是目前最优秀的架构设计, 而DataBinding是实现MVVM的最优解
2. DataBinding本身包含ViewBinding, 且不会默认为所有布局自动生成类代码量更少(仅layout标签包裹的布局)
3. 其次ViewBinding无法被封装, 需要额外的代码处理
1. 首先MVVM双向数据绑定是目前最优秀的架构设计, 而DataBinding是实现MVVM的最优解
2. ViewBinding只是DataBinding中的一个小功能, 且DataBinding不会默认为所有布局自动生成类故代码量更少


## 使用

如果你依然想用ViewBinding可以参考以下代码

### 1) 在onBind中使用

```kotlin
rv.linear().setup {
addType<SimpleModel>(R.layout.item_simple)

// 在onCreateViewHolder生命周期使用
onCreate {
val binding = ItemSimpleBinding.bind(itemView)
binding.tvName.text = "文本内容"
getBinding<ItemSimpleBinding>().tvName.text = "文本内容"
}

// 或者在onBindViewHolder生命周期中使用
onBind {
val binding = ItemSimpleBinding.bind(itemView)
val binding = getBinding<ItemSimpleBinding>()
}
}.models = getData()
```

或者在实现[ItemBind](/#2)的数据模型中使用
### 2) 在ItemBind中使用

如果使用实现接口[ItemBind](/#2)的数据模型

```kotlin
class SimpleModel(var name: String = "BRV") : ItemBind {

override fun onBind(holder: BindingAdapter.BindingViewHolder) {
val binding = ItemSimpleBinding.bind(holder.itemView)
val binding = getBinding<ItemSimpleBinding>()
binding.tvName.text = "文本内容"
}
}
```

都是调用方法`getBinding()`

## 多类型

如果是多类型注意先判断类型, 避免为绑定错误的ViewBinding

```kotlin
Expand All @@ -50,14 +58,16 @@ class SimpleModel(var name: String = "BRV") : ItemBind {
override fun onBind(holder: BindingAdapter.BindingViewHolder) {
when(holder.itemViewType) {
R.layout.item_simple -> {
val binding = ItemSimpleBinding.bind(holder.itemView)
binding.tvName.text = "文本内容"
getBinding<ItemSimpleBinding>().tvName.text = "文本内容"
}
R.layout.item_simple_2 -> {
val binding = ItemSimpleBinding2.bind(holder.itemView)
binding.tvName.text = "类型2-文本内容"
getBinding<ItemSimpleBinding2>().tvName.text = "类型2-文本内容"
}
}

getBindingOrNull<ItemSimpleBinding>()?.let {
// 该方法仅ItemSimpleBinding正确获取到才会执行, 故不需要判断item类型
}
}
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class ViewBindingFragment : Fragment(R.layout.fragment_view_binding) {
binding.rv.linear().setup {
addType<SimpleModel>(R.layout.item_simple)
onBind {
val binding = ItemSimpleBinding.bind(itemView) // 使用ViewBinding
val binding = getBinding<ItemSimpleBinding>() // 使用ViewBinding
binding.tvSimple.text = layoutPosition.toString()
}
R.id.tv_simple.onClick {
Expand Down

0 comments on commit 4501f09

Please sign in to comment.