我正在使用新的拱门.来自谷歌的组件.
我有活动登录/注册管理片段,感谢 FragmentTransaction
Activity->RegisterFragment (with ViewPager) -> RegistrationSteps (adapter)
在RegisterFragment里面我有ViewPager.我希望里面的所有页面ViewPager都使用相同的ViewModel.
这些都是注册步骤(RegistrationStepFragment),其采用母公司RegistrationFragment LifecycleOwner该范围的视图模型到它-我只是想视图模型先限定这个父片段.
RegistrationFragment.class来自
public interface FragmentViewPagerListener<T extends LifecycleFragment> {
void nextPage();
T getLifecycleFragment();
}
Run Code Online (Sandbox Code Playgroud)
RegistartionSteps(页面)来自
public abstract class RegisterStepFragment extends LifecycleFragment {
protected FragmentViewPagerListener mListener;
protected RegisterViewModel mViewModel;
public void setListener(FragmentViewPagerListener fragmentViewPagerListener) {
this.mListener = fragmentViewPagerListener;
}
protected abstract void observeViewModel();
@Override
public void onCreated(@Nullable Bundle savedInstanceState) {
super.onCreated(savedInstanceState);
mViewModel = ViewModelProviders.of(mListener.getLifecycleFragment()).get(RegisterViewModel.class);
observeViewModel();
}
protected abstract boolean validateData();
}
Run Code Online (Sandbox Code Playgroud)
一切顺利,直到我达到3页,我想向后移动(到第二页)然后抛出异常mViewPager.setCurrentItem(1) …
android android-lifecycle android-fragments android-viewmodel
我正在使用 Koin 将 viewModel 注入片段。我的应用程序是单一活动。我只需要在 servisFragment 和 partFragment 中使用 sharedViewModel。我想在用红色标记的导航后从 Activity 中清除该 viewModel。
我怎样才能做到这一点?
注入viewModel的代码
private val servisViewModel by sharedViewModel<ServisViewModel>()
Run Code Online (Sandbox Code Playgroud)
Koin 共享视图模型
inline fun <reified T : ViewModel> Fragment.sharedViewModel(
name: String? = null,
noinline from: ViewModelStoreOwnerDefinition = { activity as
ViewModelStoreOwner },
noinline parameters: ParametersDefinition? = null
) = lazy { getSharedViewModel<T>(name, from, parameters) }
Run Code Online (Sandbox Code Playgroud)
感谢您的任何帮助。
我遵循 MVVM 模式 - 这意味着我为每个 Fragment 都有一个 ViewModel。
我使用 ViewPager2添加了两个选项卡。
我的适配器看起来像这样:
@Override
public Fragment createFragment(int position) {
switch (position) {
case 0:
return new MergedItemsFragment();
case 1:
return new ValidatedMergedItemsFragment();
}
return new MergedItemsFragment();
}
Run Code Online (Sandbox Code Playgroud)
选项卡正在工作。但是,我注意到我的 MergedItemsFragment 的 ViewModel 表现得很奇怪。在我添加标签之前,我像这样导航到 Fragment:
NavHostFragment.findNavController(this).navigate(R.id.action_roomFragment_to_itemsFragment);
Run Code Online (Sandbox Code Playgroud)
当我离开那个片段NavHostFragment.findNavController(this).popBackStack()然后返回到那个片段时,我会得到一个新的空 ViewModel。这是有意的。
使用新方法,我正在使用return new MergedItemsFragment(). 当我离开那个片段并稍后返回时,我得到一个包含旧数据的 ViewModel 。这是一个问题,因为旧数据不再相关,因为用户在另一个片段中选择了不同的数据。
更新 #1
我意识到他实际上将所有旧片段保存在内存中,因为多次调用相同的打印语句。它被调用的次数随着我离开并返回该屏幕的次数而增加。因此,如果我离开并返回 10 次并旋转我的设备,他实际上会执行一行 10 次。任何猜测如何以与 ViewModels 一起工作的方式使用导航组件实现 Tabs/ViewPagers?
更新 #2
我这样设置我的 ViewModel:
@Override
public …Run Code Online (Sandbox Code Playgroud) java android android-viewmodel android-architecture-navigation android-viewpager2
我创建了一个测试活动来更新我的 MyViewModel 中的一些文本。
我想在Fragment 中观察这些变化,但是当我使用
MyViewModel myViewModel = new ViewModelProvider(this).get(MyViewModel.class);
Run Code Online (Sandbox Code Playgroud)
它给了我一个与活动中使用的不同的 MyViewModel 实例,这导致我onChanged()在片段中的回调不被调用。
只有当我将相同的片段代码修改为
HomeViewModel homeViewModel = new ViewModelProvider(getActivity()).get(HomeViewModel.class);
Run Code Online (Sandbox Code Playgroud)
片段是否获得与活动相同的 MyViewModel 实例 - 所以 onChanged()被成功调用。
但是,我不确定使用getActivity()作为 ViewModelStoreOwner 是否是正确的做事方式,因为我没有在任何地方的任何示例中看到过这种情况。我想知道在这种情况下是否应该使用更好的 ViewModelStoreOwner?
android android-fragments android-livedata android-viewmodel
我正在开发一个 Android 钢琴“测验”应用程序 - 用户点击钢琴键,然后单击黄色的“检查”按钮提交答案进行评估,并查看在钢琴上绘制的正确答案。主要QuizActivity有这样的布局:

屏幕的上部包含几个控件(文本、提交按钮等)。屏幕的下部由一个自定义PianoView组件占据,用于处理钢琴键盘的绘制。
根据MVVM原则,PianoView应该有自己的PianoViewModel,将其状态(即当前按下的键,突出显示的键等)存储在KeysStateRepository. 封闭的QuizActivity也应该有一个QuizActivityViewModel, 来处理各种控制(提交答案,跳过问题......)。将QuizActivityViewModel需要能够从查询中选择键PianoView(或者更确切地说,从它的KeysStateRepository),他们提交领域层进行评估,然后将结果发回PianoView的可视化。
换言之,所述QuizActivity的ViewModel应该拥有/是的母体PianoView的ViewModel以促进通信和数据共享。
如何建模这种父子关系以在 ViewModel 之间进行通信?
AFAIK aViewModel不能依赖于另一个ViewModel(我会通过什么ViewModelStoreOwner来获得ViewModel另一个中的 a Viewmodel?)。我认为至少用Dagger-Hilt是不可能实现的。
想到了解决此问题的三种解决方案,但都无法使用:
Android 开发文档建议使用shared ViewModel来促进两个 Fragment / Views 之间的数据共享。但是,这不适合我的用例。的PianoView(或它的视图模型)应该是其状态的具有唯一所有者Repository …
我想使用 saveStateHandle 将一些数据从活动直接传递到片段的视图模型。
在我的活动中我有:
navController.addOnDestinationChangedListener { controller, _, _ ->
controller.currentBackStackEntry?.savedStateHandle?.set(
"foo",
"bar"
)
}
Run Code Online (Sandbox Code Playgroud)
所以viewModel中的代码如下所示:
MyViewModel(state: SavedStateHandle) : ViewModel() {
init {
state
?.getStateFlow("foo", "")
?.onEach { /* do something */ }
?.launchIn(viewModelScope)
}
Run Code Online (Sandbox Code Playgroud)
由于某种原因,期望值bar永远不会被发出。
我已经检查了Fragment本身,数据就在那里:
val handle = findNavController().currentBackStackEntry?.savedStateHandle
handle?.getLiveData<String>("foo")?.observe(viewLifecycleOwner) {
// here it is
}
Run Code Online (Sandbox Code Playgroud)
但是是否有可能将数据直接传递到 viewModel 的 savingStateHandle ?我相信应该是这样,因为导航器以某种方式通过了。
android android-savedstate android-viewmodel android-jetpack-navigation viewmodel-savedstate
我正在遵循MVVM使用Android Architecture Components和Data Binding库的架构。
TL; 博士
ViewModel在复合视图中引用对象是否违反了 MVVM 架构?我查看了 Google 的示例,只看到它在 Activity/Fragment XML 中使用,但没有在自定义视图中使用。
有问题的代码
我有一个复合视图,我想在许多地方重复使用它。它从 XML 实例化。该视图根据用户输入进行填充。我想确保用户输入的任何内容都能在方向更改中幸存下来。请考虑我匆忙编写的以下代码来说明场景:
public class RestaurantActivity extends AppCompatActivity {
RestaurantViewModel viewModel;
RestaurantActivityBinding binding;
@Override
public void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
binding = DataBindingUtil.setContentView(this, R.layout.restaurant_activity );
viewModel = ViewModelProviders.of( this ).get( RestaurantViewModel.class );
//is this "legal" for MVVM
binding.selectionView.setRestaurantViewModel( viewModel );
viewModel.extraHotSause.observe ( this, new Observer() {
@Override
void onChange(Boolean extraHotSauce ) {
binding.selectionView.extraHotSauce( extraHotSauce …Run Code Online (Sandbox Code Playgroud) android mvvm android-viewmodel android-architecture-components
使用ViewModel和Databinding验证表单数据的最佳方法是什么?
我有一个简单的Sign-Up活动,该活动链接绑定布局和ViewModel
class StartActivity : AppCompatActivity() {
private lateinit var binding: StartActivityBinding
private lateinit var viewModel: SignUpViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProviders.of(this, SignUpViewModelFactory(AuthFirebase()))
.get(SignUpViewModel::class.java);
binding = DataBindingUtil.setContentView(this, R.layout.start_activity)
binding.viewModel = viewModel;
signUpButton.setOnClickListener {
}
}
}
Run Code Online (Sandbox Code Playgroud)
ViewModel4 ObservableFields和signUp()在向服务器提交数据之前应该验证数据的方法。
class SignUpViewModel(val auth: Auth) : ViewModel() {
val name: MutableLiveData<String> = MutableLiveData()
val email: MutableLiveData<String> = MutableLiveData()
val password: MutableLiveData<String> = MutableLiveData()
val passwordConfirm: MutableLiveData<String> = MutableLiveData()
fun signUp() {
auth.createUser(email.value!!, password.value!!)
}
} …Run Code Online (Sandbox Code Playgroud) validation android kotlin android-databinding android-viewmodel
这是我的 MWE 测试类,它依赖于 AndroidX、JUnit 4 和 MockK 1.9:
class ViewModelOnClearedTest {
@Test
fun `MyViewModel#onCleared calls Object#function`() = mockkObject(Object) {
MyViewModel::class.members
.single { it.name == "onCleared" }
.apply { isAccessible = true }
.call(MyViewModel())
verify { Object.function() }
}
}
class MyViewModel : ViewModel() {
override fun onCleared() = Object.function()
}
object Object {
fun function() {}
}
Run Code Online (Sandbox Code Playgroud)
注意:该方法在超类中受保护ViewModel。
我想验证MyViewModel#onCleared调用Object#function. 上面的代码通过反射实现了这一点。我的问题是:我可以以某种方式运行或模拟 Android 系统以便onCleared调用该方法,这样我就不需要反射吗?
来自onClearedJavaDoc:
当这个 ViewModel 不再使用时会调用这个方法,并且会被销毁。
那么,换句话说,我如何创建这种情况,以便我知道onCleared被调用并且我可以验证它的行为?
android unit-testing android-testing android-viewmodel android-architecture-components
在android-architecture-components/GithubBrowserSample 存储库中,Fragment#onViewCreated生命周期方法用于ViewModel实例化(具有Fragment的范围),用于Fragment使用数据绑定 + LiveData+组合的s ViewModel:
来自SearchFragment.kt该回购 ^:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
searchViewModel = ViewModelProviders.of(this, viewModelFactory)
...
}
Run Code Online (Sandbox Code Playgroud)
是否有任何官方的指南或共识哪个这些Fragment生命周期方法,如onAttach,onCreate,onViewCreated,或者onActivityCreated是实例化的最佳/最安全的地方Fragment的ViewModel使用ViewModelProviders.of(fragment, viewModelFactory)方法?(考虑到数据绑定 +LiveData组合,如果这有区别的话)
试图理解将ViewModel实例化放入任何早期生命周期方法(例如onAttach/ )的一般优点/缺点onCreate(super当然是在调用之后)。
提前致谢。
android android-fragments android-livedata android-viewmodel android-architecture-components
android ×10
android-architecture-components ×3
java ×2
kotlin ×2
mvvm ×2
android-architecture-navigation ×1
dagger-hilt ×1
koin ×1
unit-testing ×1
validation ×1