如何编写扩展函数以在Kotlin中实例化AndroidViewModel?

时间:2020-09-28 13:44:24

标签: android kotlin android-jetpack

有人为FragmentActivityViewModel编写了两个扩展函数(代码A2)以实例化Fragment,效果很好,您可以看到代码A1和代码A3。

我希望为FragmentActivityAndroidViewModel编写两个扩展函数(代码B2)以实例化class HomeViewModel_A(private val mDBVoiceRepository: DBVoiceRepository) : ViewModel() { } ,您可以看到代码B1和代码B3,该怎么办?谢谢!

代码A1

inline fun <reified T : ViewModel> Fragment.getViewModel(noinline creator: (() -> T)? = null): T {
    return if (creator == null)
        ViewModelProvider(this).get(T::class.java)
    else
        ViewModelProvider(this, BaseViewModelFactory(creator)).get(T::class.java)
}

inline fun <reified T : ViewModel> FragmentActivity.getViewModel(noinline creator: (() -> T)? = null): T {
    return if (creator == null)
        ViewModelProvider(this).get(T::class.java)
    else
        ViewModelProvider(this, BaseViewModelFactory(creator)).get(T::class.java)
}

代码A2

class FragmentHome : Fragment() {
    private val mHomeViewModel_A by lazy {
        getViewModel {
            HomeViewModel_A(provideRepository(mContext))
        }
    }

}

代码A3

class HomeViewModel_B(application: Application,private val mDBVoiceRepository: DBVoiceRepository) :  AndroidViewModel(application)  {

}

代码B1

?

代码B2

class FragmentHome : Fragment() {
  private val mHomeViewModel_B by lazy {     
       ?      
  }
}

代码B3

Container(
    child: SingleChildScrollView(
      padding: EdgeInsets.all(10.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                'Hello,',
                style: Theme.of(context)
                    .textTheme
                    .headline4
                    .apply(color: Colors.grey),
              ),
              Text(
                "Mr. Udeinya",
                style: Theme.of(context)
                    .textTheme
                    .headline4
                    .apply(color: Colors.deepOrange, fontWeightDelta: 2),
              ),
            ],
          ),
          Container(
            padding: EdgeInsets.all(20.0),
            decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(10.0),
                color: Colors.deepOrange,
                border: Border.all(
                  width: 3,
                  color: Colors.white,
                )),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text(
                  'Wallet Balance :',
                  style: TextStyle(
                    fontSize: 19,
                    fontWeight: FontWeight.bold,
                    color: Colors.white,
                  ),
                ),
                SizedBox(
                  height: 10.0,
                ),
                Container(
                  width: double.infinity,
                )
              ],
            ),
          ),
        ],
      ),
    ),
  )

2 个答案:

答案 0 :(得分:4)

Ktx Fragments库已经具有一个功能,用于简洁地创建一个懒惰的委托来检索视图模型:Fragment.viewModels()FragmentActivity.viewModels()

这些适用于具有默认构造函数(分别为空或Application参数)的ViewModel和AndroidViewModels,或者您可以使用尾随lambda返回视图模型工厂。您可以这样使用它:

class FragmentHome : Fragment() {
  private val mHomeViewModel_B: MyViewModel by viewModels()
}

class FragmentHome : Fragment() {
  private val mHomeViewModel_B: MyViewModel by viewModels { getMyViewModelFactory() }
}

要获得与 A2 中相同的功能,可以包装此函数以为您建立工厂:

@Suppress("UNCHECKED_CAST")
inline fun <reified VM : ViewModel> Fragment.viewModelFactory(crossinline creator: () -> VM): Lazy<VM> {
    return viewModels {
        object : ViewModelProvider.Factory {
            override fun <T : ViewModel?> create(modelClass: Class<T>): T {
                return creator() as T
            }
        }
    }
}

答案 1 :(得分:0)

片段Ktx

by viewModels(...)fragment-ktx库的一部分,它是创建lazy委托以获得ViewModels的便捷代表。

// creates lazy delegate for obtaining zero-argument MyViewModel
private val viewModel : MyViewModel by viewModels()
// it's functionally equal to:
private val viewModel by lazy {
    ViewModelProvider(this).get(MyViewModel::class.java)
}

// with factory:
private val viewModel : MyViewModel by viewModels { BaseViewModelFactory {  } }
// is equal to:
private val viewModel by lazy {
    ViewModelProvider(this, BaseViewModelFactory {  }).get(MyViewModel::class.java)
}

class BaseViewModelFactory(val creator: () -> ViewModel) : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return creator() as T
    }
}