如何将逻辑移动到 ViewModel?
How to move logic to ViewModel?
如何从我的 ViewModel 中的片段移动逻辑?
override fun onItemClick(titleName: Int) {
when (titleName) {
R.string.about_terms_service -> {
activity?.addFragment(
WebViewFragment.newInstance(
TERMS_LINK,
getString(R.string.about_terms_service)
)
)
}
R.string.about_open_source_licenses -> activity?.addFragment(LicensesFragment())
}
}
此逻辑可以移至 ViewModel
,但需要一些开销。当然,添加哪个片段的决定应该移到ViewModel
,但是添加片段的代码应该留在Fragment
(或Activity
)。我认为它应该看起来像这样:
片段:
override fun onItemClick(titleName: Int) {
viewModel.onTitleClick(titleName)
}
ViewModel:
fun onTitleClick(titleName: Int) {
when (titleName) {
R.string.about_terms_service -> {
postViewModelEvent(ShowWebViewFragmentEvent())
}
R.string.about_open_source_licenses -> {
// TODO: open License fragment
}
}
}
在 ViewModel
中,您应该将此 // TODO
s 替换为针对您的视图的特定命令(Fragment
、Activity
),这将触发导航到特定片段.例如,关于如何做到这一点的文章是 here(当然,任何 ViewModel
- Fragment
解决方案都可以)。
在这种情况下,可以很容易地测试这个逻辑。
如果您通过视图模型事件(在 link 中描述)将 ViewModel
与 Fragment
连接,您可以这样做:
创建一个显示 WebViewFragment
的事件,如下所示:
class ShowWebViewFragmentEvent(): ViewModelEvent {
override fun handle(activity: BaseActivity) {
super.handle(activity)
activity?.addFragment(
WebViewFragment.newInstance(
TERMS_LINK,
getString(R.string.about_terms_service)
)
)
}
}
和 post 它在你的 ViewModel
中(先替换 // TODO
),像这样:
postViewModelEvent(ShowWebViewFragmentEvent())
请注意,linked post 中的所有必需更改都应该完成。
感谢 ,但我用下一个代码修改了这个解决方案:
片段:
override fun onItemClick(titleName: Int) {
viewModel.onTitleClick(titleName)
}
视图模型:
fun onTitleClick(titleName: Int) {
when (titleName) {
R.string.about_terms_service -> {
termsOfServiceItemClickEvent.postValue(
ViewModelEvent(
WebViewFragment.newBundle(
url = TERMS_LINK,
title = appContext.getString(R.string.about_terms_service)
)
)
)
}
R.string.about_open_source_licenses -> licenseItemClickEvent.postValue(ViewModelEvent(R.string.about_open_source_licenses))
}
}
ViewModelEvent:
open class ViewModelEvent<out T>(private val content: T? = null) {
var hasBeenHandled = false
private set
/**
* Returns the content and prevents its use again.
*/
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
}
又是片段:
viewModel = ViewModelProviders
.of(this, viewModelFactory)
.get(AboutViewModel::class.java)
viewModel.licenseItemClickEvent.observe(this, Observer<ViewModelEvent<Int>> {
it?.getContentIfNotHandled()?.let { activity?.addFragment(LicensesFragment()) }
})
viewModel.termsOfServiceItemClickEvent.observe(this, Observer<ViewModelEvent<Bundle>> {
it?.getContentIfNotHandled()?.let { args ->
activity?.addFragment(WebViewFragment.newInstance(args = args))
}
})
如何从我的 ViewModel 中的片段移动逻辑?
override fun onItemClick(titleName: Int) {
when (titleName) {
R.string.about_terms_service -> {
activity?.addFragment(
WebViewFragment.newInstance(
TERMS_LINK,
getString(R.string.about_terms_service)
)
)
}
R.string.about_open_source_licenses -> activity?.addFragment(LicensesFragment())
}
}
此逻辑可以移至 ViewModel
,但需要一些开销。当然,添加哪个片段的决定应该移到ViewModel
,但是添加片段的代码应该留在Fragment
(或Activity
)。我认为它应该看起来像这样:
片段:
override fun onItemClick(titleName: Int) {
viewModel.onTitleClick(titleName)
}
ViewModel:
fun onTitleClick(titleName: Int) {
when (titleName) {
R.string.about_terms_service -> {
postViewModelEvent(ShowWebViewFragmentEvent())
}
R.string.about_open_source_licenses -> {
// TODO: open License fragment
}
}
}
在 ViewModel
中,您应该将此 // TODO
s 替换为针对您的视图的特定命令(Fragment
、Activity
),这将触发导航到特定片段.例如,关于如何做到这一点的文章是 here(当然,任何 ViewModel
- Fragment
解决方案都可以)。
在这种情况下,可以很容易地测试这个逻辑。
如果您通过视图模型事件(在 link 中描述)将 ViewModel
与 Fragment
连接,您可以这样做:
创建一个显示 WebViewFragment
的事件,如下所示:
class ShowWebViewFragmentEvent(): ViewModelEvent {
override fun handle(activity: BaseActivity) {
super.handle(activity)
activity?.addFragment(
WebViewFragment.newInstance(
TERMS_LINK,
getString(R.string.about_terms_service)
)
)
}
}
和 post 它在你的 ViewModel
中(先替换 // TODO
),像这样:
postViewModelEvent(ShowWebViewFragmentEvent())
请注意,linked post 中的所有必需更改都应该完成。
感谢
片段:
override fun onItemClick(titleName: Int) {
viewModel.onTitleClick(titleName)
}
视图模型:
fun onTitleClick(titleName: Int) {
when (titleName) {
R.string.about_terms_service -> {
termsOfServiceItemClickEvent.postValue(
ViewModelEvent(
WebViewFragment.newBundle(
url = TERMS_LINK,
title = appContext.getString(R.string.about_terms_service)
)
)
)
}
R.string.about_open_source_licenses -> licenseItemClickEvent.postValue(ViewModelEvent(R.string.about_open_source_licenses))
}
}
ViewModelEvent:
open class ViewModelEvent<out T>(private val content: T? = null) {
var hasBeenHandled = false
private set
/**
* Returns the content and prevents its use again.
*/
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
}
又是片段:
viewModel = ViewModelProviders
.of(this, viewModelFactory)
.get(AboutViewModel::class.java)
viewModel.licenseItemClickEvent.observe(this, Observer<ViewModelEvent<Int>> {
it?.getContentIfNotHandled()?.let { activity?.addFragment(LicensesFragment()) }
})
viewModel.termsOfServiceItemClickEvent.observe(this, Observer<ViewModelEvent<Bundle>> {
it?.getContentIfNotHandled()?.let { args ->
activity?.addFragment(WebViewFragment.newInstance(args = args))
}
})