0

概述 我正在尽力遵循 MVVM 模式。在我的数据模型中,我有一个实体“语言”及其通过存储库访问的相应 DAO。反过来,这个存储库提供我的视图模型,并通过我的片段中的工厂实例化。或者,从另一个方面来说,我的片段 -> ViewModelFactory -> ViewModel -> Repository -> DAO -> Entity

我对 ArrayAdapters “适合” MVVM 模式的位置感到有些困惑。特定片段旨在显示一堆字段(名称、语言等),作为应用程序中的“个人资料”创建页面。

问题: 我试图填充带有语言列表的旋转器,以便在选择旋转器中的语言时,在软件中实际使用了相应的值(思考:文本值对)。我真的不知道自己在做什么,但我正在尽可能快地失败。目前,我在片段 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;
}

@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();
}

存储库

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();
    }
    //...
}

SpinLang 适配器

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.

语言课 不要与语言混淆!

这是因为我认为使用扩展 LiveData 而不是 RxJava Single<List> 的东西可能更容易。基于此处提供的答案:When to use RxJava in Android and when to use LiveData from Android Architectural Components? (看看kzotin的回应)。这是我的尝试。

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;
    }

}

我试过的

我真的尝试过引入此处介绍的文本值对功能: Populate Spinner from LiveData (Room Database) (这让我摸不着头脑,为什么“观察”会导致问题)。

使用此处介绍的 Observable 机制: 将 Single<List<Item>> 转换为 Observable<Item>?

...以及这里的 ID 内容(我已经评论了很多来自下两个链接的代码,因为我什至没有走那么远): Android:如何将微调器绑定到自定义对象列表?Android - 将 Spinner 配置为使用数组

通常困扰我的问题是我无法使用 for-each 循环遍历 Single<List> 对象,因为当我去将“语言”对象列表转换为“语言”对象列表。

我以为我可以将语言对象作为 Singles 检索,然后在 .map 或 .flatMap 函数中将它们添加到我的 List onObservable 中,但这导致我来到这里。

问题

  1. 我对访问存储库的位置和处理 Spinner 的初始化的选择对于 MVVM 模式是否合理?我想确保我正在使用框架,而不是反对它,但我不知道我在做什么,并且使用 RxJava,感觉很好。我在想,如果我对如何更好地组织我的代码有一些指导,那么也许它会让我避免尝试做一些愚蠢的事情。

  2. 我什至应该尝试让“中级”“language.java”类工作,还是完全放弃它?换句话说,我是否应该不担心将 RxJava 转换为 LiveData 可能有什么优势(或者我认为我理解的优势)?似乎我误解了什么,混淆了我的代码,让我的生活变得比需要的更艰难。

  3. 应该怎么做?

  4. 我应该在我的 subscribeToModel 中做什么?我读过应该为服务保留业务逻辑。所以,到目前为止,在我看来,存储库应该负责将事物传递给计算,但我对如何对“填充”逻辑进行分类有点模糊,因此对对片段进行任何形式的操作犹豫不决等级。然而,这让我想知道“好吧,那应该去那里做什么??”

非常感谢您对此提出的任何建议。

4

0 回答 0