Firebase Query 从两个节点一起获取数据
Posted
技术标签:
【中文标题】Firebase Query 从两个节点一起获取数据【英文标题】:Firebase Query to fetch data from two nodes together 【发布时间】:2021-12-16 17:08:59 【问题描述】:我在 Firebase 实时数据库中有一个名为“Posts”的根节点。在其中,我有两个节点,分别称为“ImagePosts”和“TextPosts”。在“ImagePosts”(和“TextPosts”)中,我有各种帖子的 postId。在 postID 中,我拥有该特定帖子的所有详细信息,包括 postedAt(发布时间)。
我想要做的是编写一个查询以从“ImagePosts”和“TextPosts”中获取数据,并以降序/反向顺序显示所有帖子(也就是说,最后/最近发布的帖子应该显示根据“postedAt”,在我的回收站视图的顶部)。
Please click here to see database structure
为了实现这一点,我创建了一个名为 Post 的模型和两个名为“PostAdapter”和“TextPostAdapter”的适配器。我的回收站视图是“DashboardRV”。到目前为止我尝试了什么:
家庭片段代码:
public class HomeFragment extends Fragment
ShimmerRecyclerView dashboardRV;
ArrayList<Post> postList;
public HomeFragment()
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
View view = inflater.inflate(R.layout.fragment_home, container, false);
dashboardRV = view.findViewById(R.id.dashboardRv);
dashboardRV.showShimmerAdapter();
postList = new ArrayList<>();
PostAdapter postAdapter = new PostAdapter(postList, getContext());
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
dashboardRV.setLayoutManager(layoutManager);
dashboardRV.addItemDecoration(new DividerItemDecoration(dashboardRV.getContext(), DividerItemDecoration.VERTICAL));
dashboardRV.setNestedScrollingEnabled(false);
dashboardRV.setAdapter(postAdapter);
postList.clear();
database.getReference()
.child("Posts")
.child("ImagePosts")
.addValueEventListener(new ValueEventListener()
@Override
public void onDataChange(@NonNull DataSnapshot snapshot)
for (DataSnapshot dataSnapshot : snapshot.getChildren())
Post post = dataSnapshot.getValue(Post.class);
post.setPostId(dataSnapshot.getKey());
postList.add(post);
Collections.reverse(postList);
dashboardRV.hideShimmerAdapter();
postAdapter.notifyDataSetChanged();
@Override
public void onCancelled(@NonNull DatabaseError error)
);
database.getReference()
.child("Posts")
.child("TextPosts")
.addValueEventListener(new ValueEventListener()
@Override
public void onDataChange(@NonNull DataSnapshot snapshot)
postList.clear();
for (DataSnapshot dataSnapshot : snapshot.getChildren())
Post post = dataSnapshot.getValue(Post.class);
post.setPostId(dataSnapshot.getKey());
postList.add(post);
Collections.reverse(postList);
dashboardRV.hideShimmerAdapter();
textPostAdapter.notifyDataSetChanged();
@Override
public void onCancelled(@NonNull DatabaseError error)
);
但这种方法的问题在于它不会同时显示所有“TextPosts”和“ImagePosts”。它只显示打开应用程序上的所有图像帖子,然后当我更改片段并返回时,它会显示所有文本帖子。我只是卡在这里。
【问题讨论】:
您在哪里使用此代码?在片段或 ViewModel 或活动中 @DeePanShu 我已经在我的家庭片段中使用了这个代码。 您正在使用一个带有两个不同适配器的 recyclerview(dashboardRV)。这种方式适合你吗?? 是的,我明白这可能是我的问题的原因,但我想在一个 RV 中显示所有帖子。请指导我该怎么做。 【参考方案1】:一次只为一个回收器视图使用一个适配器:
以下是同时包含(图片和文本帖子)的单个适配器的代码:
postList = new ArrayList<>();
PostAdapter postAdapter = new PostAdapter(postList, getContext());
dashboardRV.setAdapter(postAdapter);
// call clear before refreshing the list
postList.clear();
database.getReference()
.child("Posts")
.child("ImagePosts")
.addValueEventListener(new ValueEventListener()
@Override
public void onDataChange(@NonNull DataSnapshot snapshot)
for (DataSnapshot dataSnapshot : snapshot.getChildren())
Post post = dataSnapshot.getValue(Post.class);
post.setPostId(dataSnapshot.getKey());
postList.add(post);
Collections.sort(postList);
dashboardRV.hideShimmerAdapter();
postAdapter.notifyDataSetChanged();
@Override
public void onCancelled(@NonNull DatabaseError error)
);
database.getReference()
.child("Posts")
.child("TextPosts")
.addValueEventListener(new ValueEventListener()
@Override
public void onDataChange(@NonNull DataSnapshot snapshot)
for (DataSnapshot dataSnapshot : snapshot.getChildren())
Post post = dataSnapshot.getValue(Post.class);
post.setPostId(dataSnapshot.getKey());
postList.add(post);
Collections.sort(postList);
dashboardRV.hideShimmerAdapter();
postAdapter.notifyDataSetChanged();
@Override
public void onCancelled(@NonNull DatabaseError error)
);
// 使 Post 类实现可与获取后的列表进行排序:
// A class 'Post' that implements Comparable
class Post implements Comparable<Post>
...
// Used to sort posts by their postedAt
public int compareTo(Post p)
return this.postedAt - p.postedAt;
...
此链接将有助于探索如何根据postedAt进行排序:Using Comparable
【讨论】:
嘿@DeePanShu 我试过你说的。问题仍然没有解决。首先,当应用打开时,Home Fragment 中只会显示图片帖子。只有当我在片段之间切换,然后回到主页片段时,才会显示图片帖子 + 文字帖子。其次,既然您建议我只为一个 RV 使用一个适配器,我如何在一个适配器中充气两个布局,因为文本发布和图像发布的布局不同。 共享 HomeFragment 的代码,对于一个适配器中的两种布局,您必须在一个适配器中使用 2 个视图持有者:***.com/a/58744127/10954249 我已经更新并包含了 Home Fragment 的代码。请检查@DeePanShu。 请将数据库节点获取代码转移到 onViewCreated() 方法并应用我的代码,我没有看到我的代码被应用。 我已经应用了你的代码。将我的帖子类更改为包含可比较的,仅使用一个适配器并将 postList.clear() 和dashboardRV.setAdapter(postAdapter) 移到顶部(只需复制粘贴您的代码)。而且我真的不明白您将代码转移到 onViewCreated() 方法的意思。对不起,我有点初学者。【参考方案2】:要在本地合并 2 个单独的 Firebase 实时数据库请求,我建议您使用 Tasks.whenAllSuccess() 方法。您可以使用以下代码行来实现这一点:
DatabaseReference imagePostsRef = database.getReference()
.child("Posts")
.child("ImagePosts");
DatabaseReference textPostsRef = database.getReference()
.child("Posts")
.child("TextPosts");
Task firstTask = imagePostsRef.get();
Task secondTask = textPostsRef.get();
Task combinedTask = Tasks.whenAllSuccess(firstTask, secondTask).addOnSuccessListener(new OnSuccessListener<List<Object>>()
@Override
public void onSuccess(List<Object> list)
//Do what you need to do with your list
);
如您所见,当覆盖“onSuccess()”方法时,结果是一个对象列表。最后,只需将列表中的每个对象映射为 Post 类型的对象,然后将新列表传递给 single 适配器。
【讨论】:
嘿克里希纳。我可以帮助您了解其他信息吗?如果您认为我的回答对您有所帮助,请考虑通过单击左侧投票箭头下方的复选标记(✔️)来接受它。应将颜色更改为绿色。我真的很感激。谢谢!以上是关于Firebase Query 从两个节点一起获取数据的主要内容,如果未能解决你的问题,请参考以下文章