概述 我正在尽力遵循 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 中,但这导致我来到这里。
问题
我对访问存储库的位置和处理 Spinner 的初始化的选择对于 MVVM 模式是否合理?我想确保我正在使用框架,而不是反对它,但我不知道我在做什么,并且使用 RxJava,感觉很好。我在想,如果我对如何更好地组织我的代码有一些指导,那么也许它会让我避免尝试做一些愚蠢的事情。
我什至应该尝试让“中级”“language.java”类工作,还是完全放弃它?换句话说,我是否应该不担心将 RxJava 转换为 LiveData 可能有什么优势(或者我认为我理解的优势)?似乎我误解了什么,混淆了我的代码,让我的生活变得比需要的更艰难。
我应该怎么做?
我应该在我的 subscribeToModel 中做什么?我读过应该为服务保留业务逻辑。所以,到目前为止,在我看来,存储库应该负责将事物传递给计算,但我对如何对“填充”逻辑进行分类有点模糊,因此对对片段进行任何形式的操作犹豫不决等级。然而,这让我想知道“好吧,那应该去那里做什么??”
非常感谢您对此提出的任何建议。