Skip to content

Commit

Permalink
update comment
Browse files Browse the repository at this point in the history
  • Loading branch information
loongwind committed Jul 24, 2022
1 parent 33e91a0 commit ae58663
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 57 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ dependencies {
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.0'
implementation 'com.loongwind.ardf:recyclerview-ext:1.0.1'
implementation 'com.loongwind.ardf:base:1.0.1'
// implementation 'com.loongwind.ardf:base:1.0.1'
// implementation project(path: ':recyclerview')
// implementation project(path: ':base')
implementation project(path: ':base')

testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
Expand Down
17 changes: 14 additions & 3 deletions base/src/main/java/com/loongwind/ardf/base/BaseBindingActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,29 @@ abstract class BaseBindingActivity<BINDING :ViewDataBinding>:AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

//创建 ViewDataBinding 实例
val binding = createDataBinding()
//绑定当前 Activity 生命周期
binding.lifecycleOwner = this
//设置 View
setContentView(binding.root)

// 初始化数据绑定
initDataBinding(binding)
}

/**
* 根据泛型 BINDING 创建 ViewDataBinding 实例
*/
private fun createDataBinding(): BINDING {
return getBindingType(javaClass)
?.getMethod("inflate", LayoutInflater::class.java)
?.invoke(null, LayoutInflater.from(this)) as BINDING
return getBindingType(javaClass) // 获取泛型类型
?.getMethod("inflate", LayoutInflater::class.java) // 反射获取 inflate 方法
?.invoke(null, LayoutInflater.from(this)) as BINDING // 通过反射调用 inflate 方法
}

/**
* 初始化数据绑定
* 子类实现该方法通过 binding 绑定数据
*/
abstract fun initDataBinding(binding: BINDING)
}
18 changes: 15 additions & 3 deletions base/src/main/java/com/loongwind/ardf/base/BaseBindingFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,32 @@ import com.loongwind.ardf.base.utils.getBindingType
*
*/
abstract class BaseBindingFragment<BINDING:ViewDataBinding>: Fragment() {

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
//创建 ViewDataBinding 实例
val binding = createDataBinding(inflater, container)
//绑定当前 Fragment 生命周期
binding.lifecycleOwner = this

// 初始化数据绑定
initDataBinding(binding)
//返回布局 View 对象
return binding.root
}

/**
* 根据泛型 BINDING 创建 ViewDataBinding 实例
*/
private fun createDataBinding(inflater: LayoutInflater, container: ViewGroup?): BINDING {
return getBindingType(javaClass)
?.getMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java)
?.invoke(null, inflater, container, false) as BINDING
return getBindingType(javaClass)// 获取泛型类型
?.getMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java) // 反射获取 inflate 方法
?.invoke(null, inflater, container, false) as BINDING // 通过反射调用 inflate 方法
}

/**
* 初始化数据绑定
* 子类实现该方法通过 binding 绑定数据
*/
abstract fun initDataBinding(binding: BINDING)

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import com.loongwind.ardf.base.event.EVENT_BACK
import com.loongwind.ardf.base.event.OnEventListener
import com.loongwind.ardf.base.ext.bind
import com.loongwind.ardf.base.utils.getViewModelType
import com.loongwind.ardf.base.utils.injectViewModel
import org.koin.android.ext.android.getKoinScope
import org.koin.androidx.viewmodel.ext.android.getViewModelFactory
import org.koin.core.annotation.KoinInternalApi
import java.lang.Exception

/**
* @Description: Databinding + ViewModel BaseActivity
Expand All @@ -22,13 +24,15 @@ open class BaseBindingViewModelActivity<BINDING : ViewDataBinding, VM : BaseView



//创建 ViewModel 变量并延迟初始化
val viewModel:VM by lazy {
createViewModel()
}

override fun initDataBinding(binding: BINDING) {
//RDF 默认自动绑定 vm。具体业务实现中在实际的视图 xml 文件中声明当前视图的 ViewModel 为
// vm 即可自动进行绑定。
//绑定 viewModel
//绑定变量为 vm。
// 具体业务实现中在实际的布局 xml 文件中声明当前视图的 ViewModel 变量为 vm 即可自动进行绑定。
binding.setVariable(BR.vm,viewModel)

}
Expand All @@ -40,21 +44,18 @@ open class BaseBindingViewModelActivity<BINDING : ViewDataBinding, VM : BaseView
}

/**
*
* @description 初始化 ViewModel 并自动进行绑定
* @param
* @return VM
*
* @return VM ViewModel 实例对象
*/
@OptIn(KoinInternalApi::class)
private fun createViewModel():VM{
val viewModel = getViewModelType(javaClass)?.let {

val scope = getKoinScope()
val viewModelFactory = getViewModelFactory(this, it.kotlin, null, null, null, scope)
ViewModelLazy(it.kotlin, { viewModelStore }, { viewModelFactory} ).value as VM
try {
//注入 ViewModel,并转换为 VM 类型
val viewModel = injectViewModel() as VM
viewModel.bind(this)
return viewModel
}catch (e:Exception){
// 抛出异常
throw Exception("ViewModel is not inject", e)
}
viewModel?.bind(this)
return viewModel!!
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package com.loongwind.ardf.base


import android.app.Activity
import androidx.activity.ComponentActivity
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.ViewModelLazy
import androidx.lifecycle.ViewModelStoreOwner
import com.loongwind.ardf.base.event.OnEventListener
import com.loongwind.ardf.base.ext.bind
import com.loongwind.ardf.base.utils.getViewModel
import com.loongwind.ardf.base.utils.getViewModelType
import com.loongwind.ardf.base.utils.injectViewModel
import org.koin.android.ext.android.getKoinScope
import org.koin.androidx.viewmodel.ext.android.getViewModelFactory
import org.koin.core.annotation.KoinInternalApi
import org.koin.core.scope.Scope
import java.lang.Exception

/**
* @Description: Databinding + ViewModel BaseFragment
Expand Down Expand Up @@ -39,19 +44,25 @@ open class BaseBindingViewModelFragment<BINDING : ViewDataBinding, VM : BaseView
*/
@OptIn(KoinInternalApi::class)
private fun createViewModel():VM{
val viewModel = getViewModelType(javaClass)?.let {

val scope = getKoinScope()
val owner: ViewModelStoreOwner = if(isShareViewModel() && this.activity is ComponentActivity){
this.activity as ComponentActivity
}else{
this
}
val viewModelFactory = getViewModelFactory(owner, it.kotlin, null, null, null, scope)
ViewModelLazy(it.kotlin, { viewModelStore }, { viewModelFactory} ).value as VM
val scope : Scope?
val owner: ViewModelStoreOwner?

val activity = this.activity ?: throw Exception("Fragment Activity is null")
if(isShareViewModel()){
scope = activity.getKoinScope()
owner = activity
}else{
scope = getKoinScope()
owner = this
}
try {
val viewModel = getViewModel(javaClass, scope, owner, viewModelStore) as VM
viewModel.bind(this)
return viewModel
} catch (e: Exception) {
throw e
}
viewModel?.bind(this)
return viewModel!!
}

override fun onEvent(eventId: Int) {
Expand All @@ -63,7 +74,7 @@ open class BaseBindingViewModelFragment<BINDING : ViewDataBinding, VM : BaseView
* @description 是否保持 ViewModel。默认创建与当前 Fragment 生命周期绑定的 ViewModel。
* 重写此方法返回 true,则创建与当前 Fragment 宿主 Activity 生命周期绑定的 ViewModel,与当前
* Activity 绑定的其他 Fragment 可共享该 ViewMoel
* @return true:保持 ViewModel 生命周期与宿主 Activity 同步,fasle:保持 ViewModel 与当前
* @return true:保持 ViewModel 生命周期与宿主 Activity 同步,false:保持 ViewModel 与当前
* Fragment 生命周期同步
*
*/
Expand Down
20 changes: 6 additions & 14 deletions base/src/main/java/com/loongwind/ardf/base/BaseViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,14 @@ import com.loongwind.ardf.base.event.Event
*/
open class BaseViewModel: ViewModel() {
var isLoading = MutableLiveData<Boolean>()
// 提示文字
var hintText = MutableLiveData<Event<String>>()
// 提示文字资源
var hintTextRes = MutableLiveData<Event<Int>>()

// 事件
var event = MutableLiveData<Event<Int>>()


fun getHintRes(): Int {
return hintTextRes.value?.getValueIfNotHandled() ?: 0
}

fun getEventId(): Int {
return event.value?.get()?:-1
}

fun getHintText(): String? {
return hintText.value?.getValueIfNotHandled()
}

protected fun postHintText(msg: String) {
hintText.value = Event(msg)
}
Expand All @@ -44,7 +34,9 @@ open class BaseViewModel: ViewModel() {
event.value = Event(eventId)
}


/**
* 返回事件
*/
fun back(){
postEvent(EVENT_BACK)
}
Expand Down
13 changes: 6 additions & 7 deletions base/src/main/java/com/loongwind/ardf/base/event/Event.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,19 @@ package com.loongwind.ardf.base.event
*/
class Event<T>(private val value: T) {

private var hasBeanHandled = false
//是否已被处理
private var handled = false

/**
*
* @description 防止粘性事件被多次消费,多个观察者场景下,只会被一个观察者消费
* @param
* @return
*
*/
fun getValueIfNotHandled(): T? {
return if (hasBeanHandled) {
return if (handled) {
// 已处理返回 null
null
} else {
hasBeanHandled = true
// 标记为已处理
handled = true
value
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,22 @@ fun BaseViewModel.bind(fragment: BaseBindingViewModelFragment<*, *>) {


fun BaseViewModel.observe( owner: LifecycleOwner, context: Context?, onEvent: (Int) -> Unit){
// 订阅提示文字变化
hintText.observe(owner){
val content = getHintText()
val content = hintText.value?.getValueIfNotHandled()
if (!content.isNullOrBlank()) {
context?.toast(content)
}
}
// 订阅提示文字资源变化
hintTextRes.observe(owner) {
val contentRes = getHintRes()
val contentRes = hintTextRes.value?.getValueIfNotHandled() ?: -1
if (contentRes > 0) {
context?.toast(contentRes)
}
}

// 订阅事件变化
event.observe(owner) {
event.value?.getValueIfNotHandled()?.let {
onEvent(it)
Expand Down
45 changes: 45 additions & 0 deletions base/src/main/java/com/loongwind/ardf/base/utils/TypeUtils.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
package com.loongwind.ardf.base.utils

import androidx.activity.ComponentActivity
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelLazy
import androidx.lifecycle.ViewModelStore
import androidx.lifecycle.ViewModelStoreOwner
import com.loongwind.ardf.base.BaseBindingViewModelActivity
import com.loongwind.ardf.base.BaseViewModel
import org.koin.android.ext.android.getKoinScope
import org.koin.androidx.viewmodel.ext.android.getViewModelFactory
import org.koin.core.annotation.KoinInternalApi
import org.koin.core.scope.Scope
import java.lang.reflect.ParameterizedType

/**
Expand All @@ -25,14 +35,49 @@ fun getViewModelType(clazz: Class<*>) : Class<out ViewModel>? {
return null
}


fun getBindingType(clazz: Class<*>) : Class<*>? {
val superclass = clazz.genericSuperclass
if (superclass is ParameterizedType ) {
//返回表示此类型实际类型参数的 Type 对象的数组
val actualTypeArguments = superclass.actualTypeArguments
return actualTypeArguments.firstOrNull {
// 判断是 Class 类型 且是 ViewDataBinding 的子类
it is Class<*> && ViewDataBinding::class.java.isAssignableFrom(it)
} as? Class<*>
}
return null
}

@OptIn(KoinInternalApi::class)
fun ComponentActivity.injectViewModel() : ViewModel?{
return getViewModel(javaClass, getKoinScope(), this, viewModelStore )

}

@OptIn(KoinInternalApi::class)
fun Fragment.injectViewModel() : ViewModel?{
return getViewModel(javaClass, getKoinScope(), this, viewModelStore )

}

/**
* @param javaClass Class类型
* @param scope koin生命周期范围
* @param owner ViewModelStoreOwner 类型,ViewModel 绑定什么周期对象,Activity、Fragment 都实现了该接口
* @param viewModelStore 存储 ViewModel 的对象
*/
@OptIn(KoinInternalApi::class)
fun getViewModel(javaClass : Class<*>,
scope: Scope,
owner: ViewModelStoreOwner,
viewModelStore: ViewModelStore) : ViewModel?{
// 获取当前 Activity 上 ViewModel 泛型的实际类型
val viewModel = getViewModelType(javaClass)?.let {
// 获取 ViewModelFactory
val viewModelFactory = getViewModelFactory(owner, it.kotlin, null, null, null, scope)
//获取注入的 ViewModel
ViewModelLazy(it.kotlin, { viewModelStore }, { viewModelFactory} ).value
}
return viewModel
}

0 comments on commit ae58663

Please sign in to comment.