使用RxJava3在房间数据库的片段中填充微调器的问题

使用RxJava3在房间数据库的片段中填充微调器的问题,java,android,android-fragments,android-spinner,rx-java3,Java,Android,Android Fragments,Android Spinner,Rx Java3,概述 我正在尽力遵循MVVM模式。在我的数据模型中,我有一个实体“languages”及其通过存储库访问的对应DAO。这个存储库反过来为我的viewmodel提供信息,并通过片段中的工厂进行实例化。或者,从另一个角度看,我的片段->视图模型工厂->视图模型->存储库->DAO->实体 对于阵列适配器“适合”MVVM模式的位置,我有点困惑。该特定片段设计用于显示一组字段(名称、语言等),作为应用程序中的“配置文件”创建页面 问题: 我试图用语言列表填充微调器,这样当选择微调器中的语言时,软件中实际

概述 我正在尽力遵循MVVM模式。在我的数据模型中,我有一个实体“languages”及其通过存储库访问的对应DAO。这个存储库反过来为我的viewmodel提供信息,并通过片段中的工厂进行实例化。或者,从另一个角度看,我的片段->视图模型工厂->视图模型->存储库->DAO->实体

对于阵列适配器“适合”MVVM模式的位置,我有点困惑。该特定片段设计用于显示一组字段(名称、语言等),作为应用程序中的“配置文件”创建页面

问题: 我试图用语言列表填充微调器,这样当选择微调器中的语言时,软件中实际会使用相应的值(想想:文本-值对)。我真的不知道我在做什么,但我正在尽可能快地失败。目前,我在fragment onViewCreated方法中遇到以下错误:

Android Studio错误:“无法解析“Observable”中的方法“observe”

代码

语言实体

@Entity
public class languages {
    @PrimaryKey(autoGenerate = true)
    @NonNull
    public Long langNo;
    public String langDesc;
    @ColumnInfo(defaultValue = "CURRENT_TIMESTAMP")
    public Long langUpdatedDate;
    @ColumnInfo(defaultValue = "CURRENT_TIMESTAMP")
    public Long langCreatedDate;
}
public class newProfileRepository {
    private final syllableDB m_db;
    private static newProfileRepository s_Instance;
    private usersDAO u_dao;
    private languagesDAO l_dao;
    private usersXlanguagesDAO uxl_dao;
    

    public newProfileRepository(final syllableDB db){
        m_db  = db;
        u_dao = m_db.usersDao();
        l_dao = m_db.languagesDAO();
        uxl_dao = m_db.usersXlanguagesDAO();
    }

    public static newProfileRepository getInstance(final syllableDB db) {
        if (s_Instance == null) {
            synchronized (newProfileRepository.class) {
                if (s_Instance == null) {
                    s_Instance = new newProfileRepository(db);
                }
            }
        }
        return s_Instance;
    }

    public Single<List<languages>> getLanguages(){
        return l_dao.getLanguages();
    }
    //...
}

DAO

@Dao
public interface languagesDAO {
    @Update
    Completable update(languages language);

    @Insert
    Completable insert(languages language);

    @Delete
    Completable delete(languages language);

    //for array deletion
    @Delete
    Completable delete(languages... language);

    //Queries
    @Query("SELECT * FROM languages;")
    Single<List<languages>> getLanguages();
}

我尝试过的

我真的尝试过使用这里介绍的文本-值对功能: (这让我摸不着头脑,为什么“观察”会引起问题)

使用此处显示的可观察机械:

…还有这里的ID内容(我已经对下面两个链接中的许多代码进行了注释,因为我还没走那么远): 和

经常困扰我的问题是,我无法遍历带有for-each循环的单个对象,因为当我将“语言”对象列表转换为“语言”对象列表时,“foreach未为RxJava定义…Single”(或类似的内容)

我以为我可以将语言对象作为单个对象检索,然后在.map或.flatMap函数中将它们添加到我的列表中,但这就是我的目的

问题

  • 对于MVVM模式,访问存储库和处理微调器初始化的位置的选择是否合理?我想确保我在使用这个框架,而不是反对它,但我不知道我在做什么,而使用RxJava,我感到非常困惑。我在想,如果我对如何更好地组织我的代码有了一些指导,那么也许它会阻止我尝试做一些愚蠢的事情

  • 我甚至应该尝试让“中间”语言.java类工作,还是完全放弃它?换句话说,我是否应该不担心将RxJava转换为LiveData会有什么好处(或者我认为我理解的是什么好处)?似乎我误解了什么,它混淆了我的代码,使我的生活比需要的困难得多

  • 我应该怎么做

  • 我应该在subscribeToModel中做什么?我已经读到,业务逻辑应该为服务保留。因此,到目前为止,在我看来,应该是存储库负责将内容传递给计算,但我对如何对“填充”逻辑进行分类有点模糊,因此对于在片段级别上进行任何形式的操作都很犹豫。然而,这让我想“好吧,那么应该去那里做什么呢?”

  • 提前非常感谢您为我们提供的任何信息

    public class SpinLangAdapter extends ArrayAdapter<language> {
    
        private Context context;
        private ArrayList<language> tvPairs = new ArrayList<>();
        private List<languages> langs;
        private newProfileRepository newP_repo;
        private syllableDB db;
    
        public SpinLangAdapter(Context context, int textViewResourceId,List<language> list){
            super(context,textViewResourceId);
            this.context = context;
            this.tvPairs = new ArrayList<language>(list);
        }
    
    
        //This isn't used as I'm not even getting this far...
        public void setLangs(List<languages> newLangs){
            langs = newLangs;
            notifyDataSetChanged();
        }
    
       /* @Override
        public int getCount(){
            return tvPairs.size();
        }
    
        @Override
        public language getItem(int position){
            return tvPairs.get(position);
        }*/
    
        @Override
        public long getItemId(int position){
           return position;
        }
    
        //SO Link: https://stackoverflow.com/questions/1625249/android-how-to-bind-spinner-to-custom-object-list   
        //again, not used (yet)
        /*@Override
        public View getView(int position, View convertView, ViewGroup parent) {        
            TextView label = (TextView) super.getView(position, convertView, parent);
            label.setTextColor(Color.BLACK);        
            label.setText(tvPairs.get(position).getLangDesc());
            return label;
        }*/
    }
    
    
    public class createNewProfileViewModel extends AndroidViewModel {
        private static final String QUERY_KEY = "QUERY";
    
        private final newProfileRepository m_Repository;
        private Single<List<languages>> m_Langs;   
    
        public createNewProfileViewModel(Application application,  newProfileRepository newProfileRepo) {
            super(application);
            m_Repository = newProfileRepo;
            m_Langs = m_Repository.getLanguages();
           
        }
       
        public Observable<List<languages>> getLangListObservable(){
            Single<List<languages>> items = m_Repository.getLanguages();
            items.flattenAsObservable(new Function<List<languages>, Iterable<?>>() {
                @Override
                public Iterable<?> apply(List<languages> languages) throws Throwable {
                    return languages;
                }
            })
            .toList();
            return null;
        }
    }
    
    public class createNewProfileFragment extends Fragment implements View.OnTouchListener,View.OnClickListener {
        private static final String LOG_TAG = com.electricbamboo.syllable.ui.createNewProfileFragment.class.getSimpleName();
        private CreateNewProfileBinding mBinding;
        private Context m_Context;
    
        private profileService PCS;
    
        private SpinLangAdapter nativeSLAdapter;
        private SpinLangAdapter targetSLAdapter;
        private List<language> spinnerListLangs;
    
        private Float tmpFZero=null;
        private Long tmpNativeLangNo = 0L;
        private ArrayList<Long> tmpTargetLangNos = new ArrayList<>();
    
        public createNewProfileFragment(){}
    
        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            m_Context = context;
        }
    
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                                    @Nullable Bundle savedInstanceState) {
            Log.d(LOG_TAG, "Starting New Profile Creation");
    
            mBinding = DataBindingUtil.inflate(getLayoutInflater(), R.layout.create_new_profile, container, false);
    
            return mBinding.getRoot();
        }
    
        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState){
            newProfileViewModelFactory factory = new newProfileViewModelFactory(requireActivity().getApplication());
    
            final createNewProfileViewModel model = new ViewModelProvider(this,factory).get(createNewProfileViewModel.class);
            mBinding.setLifecycleOwner(getViewLifecycleOwner());
    
            nativeSLAdapter = new SpinLangAdapter(m_Context, android.R.layout.simple_spinner_dropdown_item,spinnerListLangs);
            mBinding.spCreateNativeLang.setAdapter(nativeSLAdapter);
    
            targetSLAdapter = new SpinLangAdapter(m_Context, android.R.layout.simple_spinner_dropdown_item,spinnerListLangs);
            mBinding.spCreateTargetLang.setAdapter(targetSLAdapter);
    
            // Doesn't compile, error thrown here ("Cannot resolve method 'observe' in 'Observable'")
            model.getLangListObservable().observe(this, new Observer<List<languages>>(){
                @Override
                public void onChanged(@Nullable final List<languages> langs){
                    for(languages l : langs){
                        language tmpLang = null;
                        tmpLang.setLangNo(l.langNo);
                        tmpLang.setLangDesc(l.langDesc);
                        spinnerListLangs.add(tmpLang);
                    }
                    targetSLAdapter.notifyDataSetChanged();
                    nativeSLAdapter.notifyDataSetChanged();
                }
            });
    
            mBinding.spCreateNativeLang.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                @Override
                public void onItemSelected(AdapterView<?> adapterView, View view, int position, long l) {
                    language language = nativeSLAdapter.getItem(position);
                    tmpNativeLangNo = language.getLangNo();
                }
    
                @Override
                public void onNothingSelected(AdapterView<?> adapterView) {}
            });
    
            mBinding.spCreateTargetLang.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                @Override
                public void onItemSelected(AdapterView<?> adapterView, View view, int position, long l) {
                    language language = targetSLAdapter.getItem(position);
                    tmpTargetLangNos.add(language.getLangNo());
                }
    
                @Override
                public void onNothingSelected(AdapterView<?> adapterView) {}
            });
    
            subscribeToModel(model);
        }
    
        private void subscribeToModel(final createNewProfileViewModel model){
              //Fairly certain SOMETHING is supposed to go here, just unsure as to what
        }
    
      //...omitting onClick, onTouch, onStart, onPause, onResume, etc.
    
    
    public class language extends LiveData {
        private Long langNo;
        private String langDesc;
    
        //Getters
        public Long getLangNo(){
            return langNo;
        }
    
        public String getLangDesc(){
            return langDesc;
        }
    
        //Setters
        public void setLangNo(Long langNo){
            this.langNo = langNo;
        }
    
        public void setLangDesc(String langDesc){
            this.langDesc = langDesc;
        }
    
    }