简体   繁体   中英

Recycle view showing single item from firebase realtime database

My JSON is:

{
  "Ingredient": {
    "hgO9joLhmfh4Wjn7xYpyqcYmNOB3": {
      "Garlic": {
        "Expiry": "2022-11-12",
        "Ingredient": 1
      },
      "Onion": {
        "Expiry": "2022-11-12",
        "Ingredient": 1
      }
    }
  }
}

where hgO9joLhmfh4Wjn7xYpyqcYmNOB3 is the current user UID. The problem here is RecycleView shows only a single item from the database which in my case is Onion node. Why didn't it loop for each children under the fridgeRef.child(currentUserID) node?

java code

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    ingredientView = inflater.inflate(R.layout.fragment_fridge, container, false);
    
    myIngredientList = (RecyclerView) ingredientView.findViewById(R.id.ingredientList);
    myIngredientList.setLayoutManager(new LinearLayoutManager(getContext()));

    mAuth = FirebaseAuth.getInstance();
    currentUserID = mAuth.getCurrentUser().getUid();

    fridgeRef = FirebaseDatabase.getInstance().getReference().child("Ingredient");
    return ingredientView;
}

@Override
public void onStart() {
    super.onStart();

    FirebaseRecyclerOptions<fridgeItem> options
            new FirebaseRecyclerOptions.Builder<fridgeItem>()
                    .setQuery(fridgeRef , fridgeItem.class)
                    .build();

    FirebaseRecyclerAdapter<fridgeItem, fridgeViewHolder> adapter
            = new FirebaseRecyclerAdapter<fridgeItem, fridgeViewHolder>(options) {
        @Override
        protected void onBindViewHolder(@NonNull fridgeViewHolder holder, int position, @NonNull fridgeItem model) {

            fridgeRef.child(currentUserID).addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot snapshot) {

                    for(DataSnapshot dataSnapshot : snapshot.getChildren()){
                        if(snapshot.child("Garlic").hasChild("Ingredient")){
                            String itemName = "Garlic";
                            String itemExpiry = snapshot.child("Garlic").child("Expiry").getValue().toString();

                            holder.ingredName.setText(itemName);
                            holder.ingredExpiry.setText(itemExpiry);
                        }

                        if(snapshot.child("Onion").hasChild("Ingredient")){
                            String itemName = "Onion";
                            String itemExpiry = snapshot.child("Onion").child("Expiry").getValue().toString();

                            holder.ingredName.setText(itemName);
                            holder.ingredExpiry.setText(itemExpiry);
                        }
                    }
                }

                @Override
                public void onCancelled(@NonNull DatabaseError error) {

                }
            });
        }

        @NonNull
        @Override
        public fridgeViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.ingredientrecycle, parent, false);
            fridgeViewHolder viewHolder = new fridgeViewHolder(view);
            return viewHolder;
        }
    };

    myIngredientList.setAdapter(adapter);
    adapter.startListening();
}

public static class fridgeViewHolder extends RecyclerView.ViewHolder{

    TextView ingredName, ingredExpiry;

    public fridgeViewHolder(@NonNull View itemView) {
        super(itemView);

        ingredName = itemView.findViewById(R.id.itemName);
        ingredExpiry = itemView.findViewById(R.id.itemExpiry);
    }
}

ingredientrecycle.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    app:cardElevation="10dp"
    app:cardCornerRadius="12dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:weightSum="3">

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginTop="16dp"
            android:orientation="vertical"
            android:layout_weight="2">

            <TextView
                android:id="@+id/itemName"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/ingred"
                android:textSize="18sp"
                android:fontFamily="@font/roboto" />

            <TextView
                android:id="@+id/itemExpiry"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/expiry"
                android:textSize="16sp"
                android:layout_marginBottom="16dp"
                android:fontFamily="@font/roboto"/>
        </LinearLayout>

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_margin="16dp"
            android:gravity="end"
            android:layout_weight="1">

            <ImageView
                android:id="@+id/deleteBtn"
                android:layout_height="20dp"
                android:layout_width="20dp"
                android:src="@drawable/delete_icon"
                android:layout_marginEnd="32dp"/>
        </LinearLayout>
    </LinearLayout>
</androidx.cardview.widget.CardView>

fragment_fridge.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".fridge">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/fridge"
            android:textSize="22sp"
            android:layout_marginStart="32dp"
            android:layout_marginEnd="32dp"
            android:layout_marginTop="32dp"
            android:textStyle="bold"
            android:textColor="#FF5D36"
            android:fontFamily="@font/roboto"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/fridgetext"
            android:textSize="20sp"
            android:layout_marginStart="32dp"
            android:layout_marginEnd="32dp"
            android:fontFamily="@font/roboto"/>

        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:paddingStart="32dp"
                android:paddingEnd="32dp"
                android:paddingTop="32dp">

                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/ingredientList"
                    android:layout_width="match_parent"
                    android:layout_height="615dp" />

            </LinearLayout>
        </ScrollView>
    </LinearLayout>
</FrameLayout>

The adapters from FirebaseUI are designed to show a single child view for each direct child node at the path where you attach the adapter in the database.

In your case, you attach the adapter to /Ingredient , so it creates a single view for each child node of /Ingredient , which is just one child node for hgO9joLhmfh4Wjn7xYpyqcYmNOB3 . In that child node you then read handle both its Garlic and Onion properties, but you're setting their values on the same view holder - so you end up only seeing the values from Onion .


If you want to show all ingredients for /Ingredient/hgO9joLhmfh4Wjn7xYpyqcYmNOB3 , you should attach the adapter to that path and simplify its handling to:

FirebaseRecyclerOptions<fridgeItem> options
        new FirebaseRecyclerOptions.Builder<fridgeItem>()
                .setQuery(fridgeRef.child("hgO9joLhmfh4Wjn7xYpyqcYmNOB3") , fridgeItem.class)
                .build();

FirebaseRecyclerAdapter<fridgeItem, fridgeViewHolder> adapter
        = new FirebaseRecyclerAdapter<fridgeItem, fridgeViewHolder>(options) {
    @Override
    protected void onBindViewHolder(@NonNull fridgeViewHolder holder, int position, @NonNull fridgeItem model) {

        // String itemName = "Garlic"; TODO: 👈
        String itemExpiry = snapshot..child("Expiry").getValue().toString();

        holder.ingredName.setText(itemName);
        holder.ingredExpiry.setText(itemExpiry);
    }

    @NonNull
    @Override
    public fridgeViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.ingredientrecycle, parent, false);
        fridgeViewHolder viewHolder = new fridgeViewHolder(view);
        return viewHolder;
    }
};

myIngredientList.setAdapter(adapter);
adapter.startListening();

You'll still need to get the itemName from the database here. If that's not in your fridgeItem class yet, you can get it with something like getRef(position).getKey() iirc.


If you want to show all ingredients for all users, that doesn't fit with the logic of the adapters in FirebaseUI, and you're probably better off creating your own adapter.

  1. Attach a listener to /Ingredients as you already do.
  2. Loop over the getChildren() of the data snapshot to get the snapshot for each user.
  3. Loop over the children of each user snapshot to get to the individual ingredients.
  4. Add the data for each ingredient to an array list.
  5. Create an adapter on that array list

You didn't put the conditions inside the foreach loop


@Override
public void onStart() {
    super.onStart();

    FirebaseRecyclerOptions<fridgeItem> option
            for(DataSnapshot dataSnapshot : snapshot.getChildren()){

                    
                    if(snapshot.child("Garlic").hasChild("Ingredient")){
                        String itemName = "Garlic";
                        String itemExpiry = snapshot.child("Garlic").child("Expiry").getValue().toString();

                        holder.ingredName.setText(itemName);
                        holder.ingredExpiry.setText(itemExpiry);
                    }

                    if(snapshot.child("Onion").hasChild("Ingredient")){
                        String itemName = "Onion";
                        String itemExpiry = snapshot.child("Onion").child("Expiry").getValue().toString();

                        holder.ingredName.setText(itemName);
                        holder.ingredExpiry.setText(itemExpiry);
                    }
}
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM