我有一个启动三个片段的活动。第一个是加载启动画面,我只想在其中显示应用程序的名称几秒钟。第二个,在我目前的情况下,是一个收集用户名和语言的屏幕。第三个片段将收集他们想学习的语言。我试图在我的 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, fragment, 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, fragment, 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, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
Log.d(LOG_TAG, "RUNONCE: Gather Target Languages");
mBinding = DataBindingUtil.inflate(getLayoutInflater(), R.layout.runonce_select_targets, 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); //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;
}
}