英文:
Cards not updating after fetching data in Firestore
问题
我正在尝试编写一个库存管理系统的应用程序,我唯一需要做的事情是能够显示一个可以点击的类别列表,然后将您带到该类别中的产品列表。我正在使用带有RecyclerView的CardView,它们都在一个片段上操作(因为我正在使用导航抽屉)。如果我传入一个预定义的ArrayList,我可以成功显示卡片,但是当我从Firestore中获取数据时,卡片中就不会显示任何内容,尽管我仍然使用相同的ArrayList,但数据只是来自不同的来源。我仍然是Android的初学者,如果有人能帮助我,我将不胜感激。以下是我的Fragment类的代码。
package com.example.drawerplayground;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.QueryDocumentSnapshot;
import com.google.firebase.firestore.QuerySnapshot;
import java.util.ArrayList;
import java.util.HashMap;
public class InventoryFragment extends Fragment {
private TextView tv;
private HashMap<String, Object> categories;
private ArrayList<String> cats;
private FirebaseFirestore db;
private InventoryAdapter adapter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
cats = new ArrayList<>();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View inventoryView = inflater.inflate(R.layout.fragment_inventory, container, false);
RecyclerView recyclerView = (RecyclerView) inventoryView.findViewById(R.id.recycler_view);
adapter = new InventoryAdapter(getContext(), cats);
GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 2);
recyclerView.setLayoutManager(gridLayoutManager);
recyclerView.setAdapter(adapter);
getCategories();
return inventoryView;
}
public void getCategories() {
cats = new ArrayList<>();
db = FirebaseFirestore.getInstance();
db.collection("categories")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
cats.add(document.get("categoryName").toString());
Log.d("fragment", document.get("categoryName").toString());
}
adapter.notifyDataSetChanged(); // Move this line here
}
}
});
}
}
我尝试在适配器上使用 notifyDataSetChanged()
方法,并尝试将数据获取操作放在单独的函数中,如上所示。
请注意,在成功获取数据后,我将 adapter.notifyDataSetChanged();
移动到了正确的位置,以确保在数据准备好后通知适配器更新数据。
数据库结构如下,您有一个类别的集合,每个文档表示不同的类别,每个文档包含一个id和一个categoryName字段。这是一个非常基本和小型的结构,只是为了在开始实际项目之前测试潜在功能。
如果您有任何其他问题或需要进一步的帮助,请随时提问。
英文:
I am trying to write an app for an inventory management system and the one thing I need to do is to be able to display a list of categories that can be clicked on that will then take you to a list of products in that category. I am using a CardView with a RecyclerView, that both act on a fragment (as I am using a navigation drawer). I was able to get the cards to show successfully if a passed in a pre-defined ArrayList, but when I now fetch the data from Firestore, none of the cards want to appear, yet I am still using the same ArrayList, but the data is just coming from a different source. I am still a beginner in Android and would really appreciate it if someone could please help me. Here is my code for the Fragment class.
package com.example.drawerplayground;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.QueryDocumentSnapshot;
import com.google.firebase.firestore.QuerySnapshot;
import java.util.ArrayList;
import java.util.HashMap;
public class InventoryFragment extends Fragment {
private TextView tv;
private HashMap<String, Object> categories;
private ArrayList<String> cats;
private FirebaseFirestore db;
private InventoryAdapter adapter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
cats = new ArrayList<>();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View inventoryView = inflater.inflate(R.layout.fragment_inventory, container, false);
RecyclerView recyclerView = (RecyclerView) inventoryView.findViewById(R.id.recycler_view);
adapter = new InventoryAdapter(getContext(), cats);
GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 2);
recyclerView.setLayoutManager(gridLayoutManager);
recyclerView.setAdapter(adapter);
getCategories();
return inventoryView;
}
public void getCategories()
{
cats = new ArrayList<>();
db = FirebaseFirestore.getInstance();
db.collection("categories")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if(task.isSuccessful())
{
for(QueryDocumentSnapshot document : task.getResult())
{
cats.add(document.get("categoryName").toString());
Log.d("fragment", document.get("categoryName").toString());
}
}
}
});
adapter.notifyDataSetChanged();
}
}
I tried using the notifyDataSetChanged()
method for the adapter and also tried to perform the fetching of data in a separate function, as you can see above.
---EDIT---
Below you can see my basic idea of what the database structure looks like, I have a collection of categories, with each document being a different category and each document will contain an id and a categoryName field. It is a very basic and small structure for now, as my aim was to play around with the potential functionality before I started with the project itself.
答案1
得分: 2
I notice you are calling adapter.notifyDataSetChanged()
but I was not able to find where you are actually giving updated list of cats to your adapter.
You should adjust your adapter and do following changes-
Add setCatList()
method
public void setCatList(List<String> catList) {
this.catList= catList;
notifyDataSetChanged();
}
Modify your getItemCount()
method
@Override
public int getItemCount() {
if (catList!= null)
return catList.size();
else
return 0;
}
So structure of your InventoryAdapter will be as follow-
public class InventoryAdapter extends RecyclerView.Adapter<InventoryAdapter.CustomViewHolder> {
private Context context;
private List<String> catList;
public InventoryAdapter(Context context) {
this.context = context;
}
public CustomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new CustomViewHolder(LayoutInflater.from(context).inflate(R.layout.cat_item_layout, parent, false));
}
@Override
public void onBindViewHolder(@NonNull CustomViewHolder holder, int position) {
// setup binding of views
}
public void setCatList(List<String> catList) {
this.catList= catList;
notifyDataSetChanged();
}
@Override
public int getItemCount() {
if (catList!= null)
return catList.size();
else
return 0;
}
//inner class of CustomViewHolder
}
Then you there is no need to create new ArrayList<>()
under onCreate()
and onCreateView()
. This is how you will create your adapter -
adapter = new InventoryAdapter(getContext());
and getCategories()
will be as follows -
public void getCategories()
{
db = FirebaseFirestore.getInstance();
db.collection("categories")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if(task.isSuccessful())
{
List<String> cats = new ArrayList();
for(QueryDocumentSnapshot document : task.getResult()){
cats.add(document.get("categoryName").toString());
Log.d("fragment", document.get("categoryName").toString());
}
adapter.setCatList(cats ); //simply give updated cats list to recycle adapter
}
}
});
}
No need to call adapter.notifyDataSetChanged()
because that will be taken care under setCatList()
method of adapter.
If you want to preserve the catList then you can modify setCatList()
accordingly as put a if check, if there is some data already or not as follows -
public void setCatList(List<String> catList) {
if(this.catList!=null){
if(this.catList.size()!=0){
//there is some cat item inside already, take action accordingly
}
else
this.catList= catList;
}
else{
this.catList= catList;
}
notifyDataSetChanged();
}
Happy Coding !
英文:
I notice you are calling adapter.notifyDataSetChanged()
but I was not able to find where you are actually giving updated list of cats to your adapter.
You should adjust your adapter and do following changes-
Add setCatList()
method
public void setCatList(List<String> catList) {
this.catList= catList;
notifyDataSetChanged();
}
Modify your getItemCount()
method
@Override
public int getItemCount() {
if (catList!= null)
return catList.size();
else
return 0;
}
So structure of your InventoryAdapter will be as follow-
public class InventoryAdapter extends RecyclerView.Adapter<InventoryAdapter.CustomViewHolder> {
private Context context;
private List<String> catList;
public InventoryAdapter(Context context) {
this.context = context;
}
public CustomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new CustomViewHolder(LayoutInflater.from(context).inflate(R.layout.cat_item_layout, parent, false));
}
@Override
public void onBindViewHolder(@NonNull CustomViewHolder holder, int position) {
// setup binding of views
}
public void setCatList(List<String> catList) {
this.catList= catList;
notifyDataSetChanged();
}
@Override
public int getItemCount() {
if (catList!= null)
return catList.size();
else
return 0;
}
//inner class of CustomViewHolder
}
Then you there is no need to create new ArrayList<>()
under onCreate()
and onCreateView()
. This is how you will create your adapter -
adapter = new InventoryAdapter(getContext());
and getCategories()
will be as follows -
public void getCategories()
{
db = FirebaseFirestore.getInstance();
db.collection("categories")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if(task.isSuccessful())
{
List<String> cats = new ArrayList();
for(QueryDocumentSnapshot document : task.getResult()){
cats.add(document.get("categoryName").toString());
Log.d("fragment", document.get("categoryName").toString());
}
adapter.setCatList(cats ); //simply give updated cats list to recycle adapter
}
}
});
}
No need to call adapter.notifyDataSetChanged()
because that will be taken care under setCatList()
method of adapter.
If you want to preserve the catList then you can modify setCatList()
accordingly as put a if check, if there is some data already or not as follows -
public void setCatList(List<String> catList) {
if(this.catList!=null){
if(this.catList.size()!=0){
//there is some cat item inside already, take action accordingly
}
else
this.catList= catList;
}
else{
this.catList= catList;
}
notifyDataSetChanged();
}
Happy Coding !
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论