标签: android-viewmodel

LiveData:从 Observer lambda 内部删除观察者

在我的片段中,我观察到一个实时数据:

 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 中的观察者吗?

android kotlin android-livedata android-viewmodel

7
推荐指数
2
解决办法
6050
查看次数

引起:org.koin.core.error.InstanceCreationException:无法为 [type:Factory,primary_type 创建实例

我正在开发新闻应用程序我已经在片段类中使用 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)

android mvvm fragment android-viewmodel koin

7
推荐指数
1
解决办法
2万
查看次数

测试导航组件:“没有 NavController”

我正在实施 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

7
推荐指数
1
解决办法
3247
查看次数

如何从 AbstractSavedStateViewModelFactory 动态设置包

我的视图模型工厂

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

7
推荐指数
1
解决办法
2196
查看次数

带有 SavedState 的 AndroidViewModel

我需要使用一个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

7
推荐指数
1
解决办法
2040
查看次数

Android 在片段和对话框片段之间共享 ViewModel?

如何在对话框和对话框片段之间共享相同的视图模型?我知道 viewModel 可以在活动范围内共享。但对我来说范围太大了。

 private val model: SharedViewModel by activityViewModels()
Run Code Online (Sandbox Code Playgroud)

不幸的是,我没有项目导航组件。

android mvvm android-fragments android-dialogfragment android-viewmodel

7
推荐指数
1
解决办法
1779
查看次数

Hilt viewModel 和 Compose 不能一起工作

官方 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

7
推荐指数
1
解决办法
4958
查看次数

撰写创建新的 ViewModel 实例

我所在的项目正在慢慢采用 Jetpack Compose。它主要是一个单一的ActivityFragment应用程序,我们使用 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)

android android-viewmodel android-jetpack-compose

7
推荐指数
1
解决办法
3995
查看次数

Android ViewModel 协程启动测试不等待

我正在尝试使用 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

7
推荐指数
1
解决办法
2160
查看次数

禁止注入 @HiltViewModel 类,因为它无法正确创建 ViewModel 实例

我试图将用 @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-viewmodel dagger-hilt

7
推荐指数
1
解决办法
3110
查看次数