如何解决RxJava Observable 跨片段使用共享 ViewModel
我有一个启动三个片段的活动。 第一个是加载启动画面,我只想在其中显示应用程序的名称几秒钟。 第二个,在我目前的情况下,是一个收集用户姓名和语言的屏幕。 第三个片段将收集他们想要学习的语言。我正在尝试在我的 viewmodel 中使用 Observable 来保存我的数据,但是在切换到第二个片段时,在第一个片段中输入的信息会丢失。
我想我同时遇到了两个(或更多)问题:
- 我认为我没有在片段之间正确共享我的 runOnceviewmodel
- 我认为我使用 Observables 的方式不太正确。
从初始屏幕检查权限后,我触发一个函数 (launchProfile) 加载下一个片段,如下所示:
public void launchProfile(){
if(model.getLearnerPK() > 0){
learningScreenFragment fragment = new learningScreenFragment(model.getUser());
getParentFragmentManager()
.beginTransaction()
.addToBackStack(null)
.replace(R.id.fragment_container,fragment,null)
.commit();
} else {
runOnceNameAndNativeLangFragment fragment = new runOnceNameAndNativeLangFragment();
getParentFragmentManager()
.beginTransaction()
.addToBackStack(null)
.replace(R.id.fragment_container,null)
.commit();
}
}
由于这是一个新用户,主键将为 0,因此我加载了 runOnceNameAndNativeLangFragment:
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,@Nullable ViewGroup container,@Nullable Bundle savedInstanceState) {
Log.d(LOG_TAG,"RUNONCE: Gather Name and Native Language");
mBinding = DataBindingUtil.inflate(getLayoutInflater(),R.layout.runonce_name_native,container,false);
TransitionInflater TI = TransitionInflater.from(requireContext());
setEnterTransition(TI.inflateTransition(R.transition.slide_right));
return mBinding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view,@Nullable Bundle savedInstanceState){
runOnceviewmodelFactory factory = new runOnceviewmodelFactory(requireActivity().getApplication());
model = new viewmodelProvider(this,factory).get(runOnceviewmodel.class);
//super.onViewCreated(view,savedInstanceState); //remains of a road I tried to go down,but perhaps should have gone farther...
//model = new viewmodelProvider(requireActivity()).get(runOnceviewmodel.class);
ArrayList<language> spinnerListLangs = model.getLangList();
nativeSLAdapter = new SpinLangAdapter(m_Context,android.R.layout.simple_spinner_dropdown_item,spinnerListLangs);
mBinding.spCreateNativeLang.setAdapter(nativeSLAdapter);
mBinding.spCreateNativeLang.setonItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView,View view,int position,long l) {
language lang = nativeSLAdapter.getItem(position);
tmpNativeLangNo = lang.getLangNo();
}
@Override
public void onnothingSelected(AdapterView<?> adapterView) {}
});
mBinding.btnNext.setonClickListener(this::onClick);
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.btnNext) {
String tmpName = mBinding.etCreateProfileName.getText().toString();
if(tmpNativeLangNo != null && !tmpName.equals("")){
model.getNewUser().observeOn(Schedulers.io()) //I'm doing something dumb here
.map(user -> {
user.setName(tmpName);
user.setNativeLang(tmpNativeLangNo);
return user;
});
runOnceSelectTargetLangsFragment fragment = new runOnceSelectTargetLangsFragment();
getParentFragmentManager()
.beginTransaction()
.addToBackStack(null)
.replace(R.id.fragment_container,null)
.commit();
} else {
Toast.makeText(m_Context,"Name and Native Language required.",Toast.LENGTH_SHORT).show();
}
}
}
如果我在“runOnceSelectTargetLangsFragment fragment = new runOnceSelectTargetLangsFragment();”上设置断点然后我可以验证 model.getNewUser() 返回一个 Observable ,其中包含我在 UI 上输入的任何内容的名称和母语。让我失望的是,一旦我加载下一个片段 (runOnceSelectTargetLangsFragment),并尝试将目标语言保存在其点击处理程序中,名称和母语信息就会丢失。唉,我没有正确地共享视图模型(或者,更糟糕的是,我在不应该使用的时候使用了 Observable —— 旁注:我选择使用 Observable 是因为它使处理线程变得更加容易,并且我想随着应用程序变得越来越复杂,我会欣赏它的灵活性。至少,这是我告诉自己的。)
选择目标片段
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,"RUNONCE: Gather Target Languages");
mBinding = DataBindingUtil.inflate(getLayoutInflater(),R.layout.runonce_select_targets,@Nullable Bundle savedInstanceState){
//runOnceviewmodelFactory factory = new runOnceviewmodelFactory(requireActivity().getApplication());
//model = new viewmodelProvider(this,factory).get(runOnceviewmodel.class); //I think this was on the right track...maybe?
//super.onViewCreated(view,savedInstanceState);
model = new viewmodelProvider(requireActivity()).get(runOnceviewmodel.class);
mBinding.btnNext.setonClickListener(this::onClick);
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.btnNext) {
if(hasChecked()){
model.getNewUser().observeOn(Schedulers.io())
.subscribe(user -> {
user.setTargetLangs(getTargetLangs());
});
String restHereWearyTraveler = ""; //the inn :)
//...do more stuff
} else {
Toast.makeText(m_Context,"You must select at least one target language.",Toast.LENGTH_SHORT).show();
}
}
}
在客栈,model.getNewUser() 返回一个 Observable,目标语言全部设置,但名称和母语信息不存在。
查看模型
public class runOnceviewmodel extends Androidviewmodel {
private final profileRepository m_Repository;
private profileService PCS;
private ArrayList<language> m_Langs;
private Observable<User> newUser;
public runOnceviewmodel(Application application,profileRepository newProfileRepo) {
super(application);
m_Repository = newProfileRepo;
m_Langs = m_Repository.getLanguages();
PCS = profileService.getInstance(m_Repository);
}
public Observable<User> getNewUser(){
if(newUser == null){
User tmpuser = new User();
newUser = Observable.just(tmpuser);
}
return newUser;
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。