微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

RxJava Observable 跨片段使用共享 ViewModel

如何解决RxJava Observable 跨片段使用共享 ViewModel

我有一个启动三个片段的活动。 第一个是加载启动画面,我只想在其中显示应用程序的名称几秒钟。 第二个,在我目前的情况下,是一个收集用户姓名和语言的屏幕。 第三个片段将收集他们想要学习的语言。我正在尝试在我的 viewmodel 中使用 Observable 来保存我的数据,但是在切换到第二个片段时,在第一个片段中输入的信息会丢失。

我想我同时遇到了两个(或更多)问题:

  1. 我认为我没有在片段之间正确共享我的 runOnceviewmodel
  2. 我认为我使用 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 举报,一经查实,本站将立刻删除。