【发布时间】:2021-10-25 13:06:43
【问题描述】:
现在,我有一个有效的 ListView,它成功地加载了 ListView 中的每个“父”对象,检索父属性并在每个元素中显示它们。由于我试图关注Android's Model-View-ViewModel architecture patterns,我正在使用 RoomDb、一个 Repository 类和一个 ViewModel 类(viewmodel 类包含父子类的逻辑;我想知道这是否是反模式;但这可能是一个主题另一个问题)。
无论如何,由于我必须进行查询来检索包含 POJO 列表的 LiveData 对象,这将我可以在 ListView 上显示的数据限制为仅父字段,因为 POJO 仅包含父表的字段;由于某种原因,对每个 parentID 进行查询以检索某种循环中的所有子对象听起来并不好。因此,在互联网上搜索此内容时,我发现(但我不记得在哪里)这种方法可以制作某种同时包含父母和孩子的“关系实体”:
import androidx.room.Embedded;
import androidx.room.Relation;
import java.io.Serializable;
import java.util.List;
public class ParentWithChildren implements Serializable {
@Embedded public Parent parent;
@Relation(
parentColumn = "id",
entityColumn = "parent_id"
)
public List<Child> children;
}
然后,从我的 ParentDao,我添加了这个:
// XXX The old DAO searcher that already works for retrieving
// just the parent POJOs
@Query("SELECT * FROM parent WHERE parent_field1 = :search OR parent_field2 = :search_no_accents")
LiveData<List<Parent>> searchParents(String search, String search_no_accents);
// XXX The new method I'd like to create
@Transaction
@Query("SELECT * FROM parent WHERE parent_field1 = :search OR parent_field2 = :search_no_accents")
LiveData<List<ParentWithChildren>> searchParentsWithChildren(String search, String search_no_accents);
而且,在我的 Repository 类中:
public LiveData<List<ParentWithChildren>> searchParentsWithChildren(String search, String search_no_accents) {
return parent_dao.searchParentsWithChildren(search, search_no_accents);
}
...这是我的 ParentViewModel 从存储库中检索列表的方法:
public LiveData<List<ParentWithChildren>> searchParentsWithChildren(String search) {
// I remove accents from user search with and ad-hoc method
String search_no_accents = removeAccents(search);
return repository.searchParentsWithChildren(search, search_no_accents);
}
在我的 MainActivity 中,我有一个 SearchView 来处理用户的搜索:
SearchView search_view = findViewById(R.id.searchView);
search_view.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
if (query.equals("")) {
loadFullListFragment();
} else {
search_results = parent_viewmodel.searchParents(query);
//search_with_children = parent_viewmodel.searchParentsWithChildren(query);
observeSearchResults(search_results);
//observeSearchResults(search_with_children);
}
return true;
}
});
我的 observeSearchResults 方法也在 MainActivity 中,根据结果列表的大小加载适当的片段:
private void observeSearchResults(LiveData<List<Parent>> parents_results) {
//private void observeSearchResults(LiveData<List<ParentWithChildren>> parents_with_children) {
parents_results.observe(this, new Observer<List<Parent>>() {
//parents_with_children.observe(this, new Observer<List<ParentWithChildren>>() {
@Override
//public void onChanged(List<ParentWithChildren> parents) {
public void onChanged(List<Parent> parents) {
if ( parents.size() > 1 ) {
// ## List view of multiple results
listFragment = ParentsListFragment.newInstance( (ArrayList)parents );
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragmentContainer, listFragment);
transaction.addToBackStack(null);
transaction.commit();
}
else if ( parents.size() > 0 ) {
// TODO XXX This is kinda hacky
loadParentProfileFragment(parents.get(0));
} else {
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragmentContainer, insertFragment);
transaction.addToBackStack(null);
transaction.commit();
}
}
});
}
嗯,你看到那些被注释掉的代码行了吗?这是我要引入的新变化,以开始使用新的 ParentWithChildren 实体。 它们被注释掉了,因为它们正上方或下方的那些已经在 ListView 中显示父对象。因此,当我尝试实施更改时,我注释掉旧的那些和“dis-comment-out”那些有ParentWithChildren变化的。我必须更改这么多类来实现一个单一的更改...嗯...这里闻起来像Shotgun Surgery...:-(
...嗯,长话短说,我尝试在加载 ListView 的 Fragment 中将之前的 List<Parent> 替换为 List<ParentWithChildren>,因此每个列表元素也将能够检索与父相关的子对象并显示他们。但是,上次我尝试以这种方式实现 ParentWithChildren 实体时,它因异常而崩溃(这绝对让我大吃一惊):
java.lang.NoClassDefFoundError: 解析失败:com/mydomain/myapp/daos/ParentDao_Impl$5;
此异常的 Traceback 始于此自动生成的 ParentDao_Implement 中的某行,并且 Traceback 的下一行指向我的新 Repository.searchParentsWithChildren 方法。 我完全不知道我是否做错了,或者如何处理这个奇怪的失败。
我的 ArrayAdapter 以及我希望它变成的样子
这个 sn-p 显示了我当前工作的 ArrayAdapter,以及注释掉的代码行,或多或少地显示了我想要引入的更改:
public class ParentsArrayAdapter extends ArrayAdapter<Parent> {
//public class ParentsArrayAdapter extends ArrayAdapter<ParentWithChildren> {
//public ParentsArrayAdapter(Context context, List<ParentWithChildren> parents) {
public ParentsArrayAdapter(Context context, List<Parent> parents) {
super(context, 0, parents);
}
@Override
public View getView(int position, View convertView, ViewGroup vgroup) {
// Get the data item for this position
Parent parent = getItem(position);
//ParentWithChildren parent = getItem(position);
// XXX TODO Load child attributes list
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext())
.inflate(R.layout.listview_parents, vgroup, false);
}
// Lookup view for data population
TextView parentField1 = convertView.findViewById(R.id.list_parentField1);
// Populate the data into the template view using the data object
parentField1.setText(parent.getField1());
//parentField1.setText(parent.parent.getField1());
TextView parentField2 = convertView.findViewById(R.id.list_parentField2);
parentField2.setText(parent.getField2());
//pinyinText.setText(parent.parent.getField2());
// TODO Load first 5-10 childs here (when ParentWithChildren works)
TextView childrenCommaListField = convertView.findViewById(R.id.list_childsCommaList);
/*
¿¿?? SebasSBM is confused
*/
// Return the completed view to render on screen
return convertView;
}
}
在 PC 应用程序中,这就像执行某种 sqlSELECT p.*, c.* FROM parent AS p INNER JOIN child as c ON p.id = c.parent_id WHERE bla bla bla 一样简单:但使用 RoomDB,我感觉关系数据库的一切都复杂得多。
那么,我怎样才能让 ListView 在每个父列表的元素中加载子字段,所以它或多或少看起来像这样?任何帮助表示赞赏:
sorry, I am terrible making examples sometimes
------------
parent1 ---> parent_field1 ---> child1, child2, child3
------------
parent2 ---> parent_field1 ---> child4, child5, child6
数据库的表结构(或多或少)
Parent table
+------+--------+--------+-
| ID | field1 | field2 | [...]
+------+--------+--------+-
| | | |
+------+--------+--------+-
Child table (relation One2Many by FK)
+------+-----------+--------+---------+-
| ID | parent_id | field1 | field2 | [...]
+------+-----------+--------+---------+-
| | | | |
+------+-----------+--------+---------+-
【问题讨论】:
-
我可能错了,但我知道这不会像这样工作。您需要为 ParentWithChildren 创建另一个实体(表)并通过 ParentWithChildrenDao 与他们合作。
-
那么,如果我理解你的话,这意味着新的“交易-父-子”实体也需要自己的道,先生?
-
我很迷茫你想要实现什么以及你的问题是什么:D 为了对你的知识做一个小小的澄清,这里解释了为什么 Room 不像普通的 SQL 数据库developer.android.com/training/data-storage/room/…跨度>
-
简而言之,我的问题是我只知道如何获取从单个表中检索数据行的 POJO,但我之前从未尝试过使用这些“事务”实体之一。而且我担心让 ListView 的 ArrayAdapter 访问每个 Parent 1 by 1 的 DAO 以检索每个父母的孩子将是一个糟糕的电话......
-
欧。现在我明白了。我从一开始就没有遇到过这种情况,因为 Room 不支持这种方法。但现在看来这是可能的。我想这篇文章会对你有所帮助。它不足以成为一个答案,所以只是作为评论享受它;)medium.com/androiddevelopers/…
标签: java android relational-database android-room