在我的片段中,我观察到一个实时数据:
viewModel.emailValid.observe(
this,
Observer<GenericResponse> {
dismissProgressBar()
if (it != null && it.success) {
findNavController().navigate(R.id.action_navigatesomewhere)
}
}
)
Run Code Online (Sandbox Code Playgroud)
现在在调用navigate()之前,我想从viewModel.emailValid 中删除观察者,并且我已经看到需要观察者作为参数的可用removeObserver方法。可以以某种方式引用观察者 lambda 中的观察者吗?
我正在开发新闻应用程序我已经在片段类中使用 viewmodel 实现了 koin 但是当我在模拟器上测试代码时出现以下错误
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:557)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:922)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:922)
Caused by: org.koin.core.error.InstanceCreationException: Could not create instance for [type:Factory,primary_type:'yodgorbek.komilov.musobaqayangiliklari.viewmodel.MainViewModel']
at org.koin.core.instance.DefinitionInstance.create(DefinitionInstance.kt:61)
at org.koin.core.instance.FactoryDefinitionInstance.get(FactoryDefinitionInstance.kt:37)
at org.koin.core.definition.BeanDefinition.resolveInstance(BeanDefinition.kt:70)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:165)
at org.koin.core.scope.Scope.get(Scope.kt:128)
at org.koin.androidx.viewmodel.ViewModelResolutionKt$createViewModelProvider$1.create(ViewModelResolution.kt:66)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:164)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:130)
at org.koin.androidx.viewmodel.ViewModelResolutionKt.getInstance(ViewModelResolution.kt:43)
at org.koin.androidx.viewmodel.ViewModelResolutionKt.getViewModel(ViewModelResolution.kt:23)
at org.koin.androidx.viewmodel.ext.android.LifecycleOwnerExtKt.getViewModel(LifecycleOwnerExt.kt:85)
at yodgorbek.komilov.musobaqayangiliklari.ui.TopHeadlinesFragment$$special$$inlined$viewModel$1.invoke(LifecycleOwnerExt.kt:95)
at yodgorbek.komilov.musobaqayangiliklari.ui.TopHeadlinesFragment$$special$$inlined$viewModel$1.invoke(Unknown Source:0)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at yodgorbek.komilov.musobaqayangiliklari.ui.TopHeadlinesFragment.getViewModel(Unknown Source:7)
at yodgorbek.komilov.musobaqayangiliklari.ui.TopHeadlinesFragment.initViewModel(TopHeadlinesFragment.kt:57)
at yodgorbek.komilov.musobaqayangiliklari.ui.TopHeadlinesFragment.onCreateView(TopHeadlinesFragment.kt:51)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2600)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:881)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869) …Run Code Online (Sandbox Code Playgroud) 我正在实施 Espresso 测试。我正在使用带有NavGraph作用域的 Fragment ViewModel。问题是当我尝试测试时,Fragment我得到了一个,IllegalStateException因为Fragment没有NavController设置。我该如何解决这个问题?
class MyFragment : Fragment(), Injectable {
private val viewModel by navGraphViewModels<MyViewModel>(R.id.scoped_graph){
viewModelFactory
}
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
//Other stuff
}
Run Code Online (Sandbox Code Playgroud)
测试类:
class FragmentTest {
class TestMyFragment: MyFragment(){
val navMock = mock<NavController>()
override fun getNavController(): NavController {
return navMock
}
}
@Mock
private lateinit var viewModel: MyViewModel
private lateinit var scenario: FragmentScenario<TestMyFragment>
@Before
fun prepareTest(){
MockitoAnnotations.initMocks(this)
scenario = launchFragmentInContainer<TestMyFragment>(themeResId = R.style.Theme_AppCompat){
TestMyFragment().apply {
viewModelFactory …Run Code Online (Sandbox Code Playgroud) android android-testing android-espresso android-viewmodel android-architecture-components
我的视图模型工厂:
class ViewModelFactory @Inject constructor(
private val viewModelMap: MutableMap<Class<out ViewModel>, ViewModelAssistedFactory<out ViewModel>>,
owner: SavedStateRegistryOwner,
defaultArgs: Bundle?
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
@Throws(IllegalStateException::class)
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(key: String, modelClass: Class<T>, handle: SavedStateHandle): T {
return viewModelMap[modelClass]?.create(handle) as? T ?: throw IllegalStateException("Unknown ViewModel class")
}
}
Run Code Online (Sandbox Code Playgroud)
活动:
@Inject
lateinit var viewModelFactory: ViewModelFactory
protected val viewModel: ViewModel by lazy { ViewModelProvider(this, viewModelFactory).get(getViewModelClass()) }
Run Code Online (Sandbox Code Playgroud)
视图模型:
@AssistedInject.Factory
interface Factory : ViewModelAssistedFactory<SplashViewModel>
Run Code Online (Sandbox Code Playgroud)
我想知道如何动态提供 defaultArgs 而不是:
活动模块
@Module
companion object …Run Code Online (Sandbox Code Playgroud) android android-lifecycle dagger-2 android-viewmodel viewmodel-savedstate
我需要使用一个AndroidViewModelwith 应用程序上下文和一个SavedStateHandle. 我已经将它与应用程序上下文一起使用了,但是我无法向SavedStateHandle它添加 a 。
这就是我所拥有的,只有应用程序上下文:
// A1. get ViewModel in Fragment
val viewModel = ViewModelProvider(viewLifecycleOwner).get(MyViewModel::class.java)
// A2. MyViewModel derives from my custom BaseAndroidViewModel
class MyViewModel(application: Application) :BaseAndroidViewModel(application)
// A3. BaseAndroidViewModel in turn derives from AndroidViewModel
open class BaseAndroidViewModel(application: Application) : AndroidViewModel(application)
Run Code Online (Sandbox Code Playgroud)
对于这个问题,我认为这可能会简化为:
// B1. get ViewModel in Fragment
val viewModel = ViewModelProvider(viewLifecycleOwner).get(MyViewModel::class.java)
// B2. BaseAndroidViewModel in turn derives from AndroidViewModel
class MyViewModel(application: Application) : AndroidViewModel(application)
Run Code Online (Sandbox Code Playgroud)
那么,对于还有一个SavedStateHandlein MyViewModel,我将如何修改片段中的调用(B1示例代码中的行)?我需要明确调用工厂SavedStateViewModelFactory …
android factory android-viewmodel android-architecture-components
如何在对话框和对话框片段之间共享相同的视图模型?我知道 viewModel 可以在活动范围内共享。但对我来说范围太大了。
private val model: SharedViewModel by activityViewModels()
Run Code Online (Sandbox Code Playgroud)
不幸的是,我没有项目导航组件。
android mvvm android-fragments android-dialogfragment android-viewmodel
官方 Android文档中使用 Compose、Hilt 和 ViewModel 注入与导航的方式似乎不起作用。
我有以下设置:
主屏幕,仅承载导航控制器。主屏幕显示一个按钮。导航到具有视图模型的名称屏幕。
@Composable
fun MainScreen() {
val navController = rememberNavController()
NavHost(navController, startDestination = "home") {
composable("home") {
HomeScreen() {
navController.navigate("my/Name")
}
}
composable("my/{name}") { navBackStackEntry ->
val viewModel: NameScreenViewModel = hiltViewModel(navBackStackEntry)
NameScreen(viewModel)
}
}
}
Run Code Online (Sandbox Code Playgroud)
@Composable
fun HomeScreen(onButtonClicked: () -> Unit) {
Button(onClick = onButtonClicked, modifier = Modifier.padding(8.dp)) {
Text("Continue")
}
}
Run Code Online (Sandbox Code Playgroud)
@HiltViewModel
class NameScreenViewModel @Inject constructor(private val test: TestClass): ViewModel() {
var name = MutableLiveData("empty")
fun change() {
name.value = test.load()
} …Run Code Online (Sandbox Code Playgroud) android android-viewmodel android-jetpack-compose dagger-hilt
我所在的项目正在慢慢采用 Jetpack Compose。它主要是一个单一的Activity多Fragment应用程序,我们使用 Android 的导航组件来处理到每个屏幕的转换 ( Fragment)。只要有可能,我们就只用Fragment可组合项替换 s' XML 布局。
截至目前,案件处理情况如下:
A.sFragment显示可组合项并处理导航:
class ScreenFragment : Fragment() {
// For observing events that trigger navigation
private val viewModel by lazyViewModel { ScreenViewModel() }
override fun onCreateView( ... ): View {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(DisposeOnLifecycleDestroyed(viewLifecycleOwner))
setContent {
AppTheme {
Screen(onBackPressed = { findNavController().navigateUp() })
}
}
}
}
...
}
Run Code Online (Sandbox Code Playgroud)
B. 处理其他与 UI 相关的所有内容的可组合项:
@Composable
fun CreatePassword(
onBackPressed: () -> Unit,
) { …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用 Kotlin(1.6.21) Coroutines(1.6.4) 和 Kotlin Flow 进行 ViewModel 测试。
遵循官方Kotlin 协程测试文档,但ViewModel 在测试完成之前不会等待/返回挂起函数的结果。已经浏览了 StackOverflow 的热门答案,并尝试了所有建议的解决方案,例如注入相同的内容CoroutineDispatcher,并传递相同的内容CoroutineScope,但到目前为止没有一个有效。所以在这里我发布当前的简单测试实现。必须发布测试用例中涉及的所有类代码以获得更好的想法。
ReferEarnDetailViewModel.kt:
注入 Usecase 和 CoroutineContextProvider 并使用 viewModelScope 和提供的调度程序调用 API。但是从测试用例调用callReferEarnDetails()后,它不会收集模拟用例方法发出的任何数据。已尝试使用直接 repo 方法调用,也没有 Kotlin 流程,但同样失败。
@HiltViewModel class
ReferEarnDetailViewModel @Inject constructor(
val appDatabase: AppDatabase?,
private val referEarnDetailsUseCase: ReferEarnDetailsUseCase,
private val coroutineContextProvider: CoroutineContextProvider) : BaseViewModel() {
fun callReferEarnDetails() {
setProgress(true)
viewModelScope.launch(coroutineContextProvider.default + handler) {
referEarnDetailsUseCase.execute(UrlUtils.getUrl(R.string.url_referral_detail))
.collect { referEarnDetail ->
parseReferEarnDetail(referEarnDetail)
}
}
}
private fun parseReferEarnDetail(referEarnDetail:
ResultState<CommonEntity.CommonResponse<ReferEarnDetailDomain>>) {
when (referEarnDetail) …Run Code Online (Sandbox Code Playgroud) android kotlin android-testing android-viewmodel kotlin-coroutines
我试图将用 @HiltViewModel 注释的 ViewModel 注入到 Fragment 中并收到以下错误:
Injection of an @HiltViewModel class is prohibited since it does not create a ViewModel instance correctly.
Access the ViewModel via the Android APIs (e.g. ViewModelProvider) instead.
Injected ViewModel: com.example.MyViewModel
Run Code Online (Sandbox Code Playgroud)
这是否意味着我不应该使用 Hilt 将 ViewModel 注入到 Fragment 中?- 或者是旧的警告已经在最新版本的库中修复。
android ×9
android-architecture-components ×2
dagger-hilt ×2
kotlin ×2
mvvm ×2
dagger-2 ×1
factory ×1
fragment ×1
koin ×1