【问题标题】:When I calculate an average rating of foods, save this value to an food object it displays as 0.0当我计算食物的平均评分时,将此值保存到显示为 0.0 的食物对象中
【发布时间】:2020-06-14 13:47:21
【问题描述】:

在我的实时数据库 (Firebase) 中,我有两个“集合”,一个用于 essen(食物),一个用于 bewertung(食物评级)

我尝试在我的应用中显示每种食物的数据,这适用于食物的名称和价格(Preis)

因此我根据控制台中显示的值计算每种食物的平均评分

但是当我尝试访问每种食物的平均值时,将其设置为 TextView,平均值为 0.0,这是默认的浮点值。 但是食物的所有其他价值都正确显示(名称和价格)

这是我的片段 java 类,我在其中计算平均值并设置从 firebase 检索的所有值:

public class Aktuelle_Bewertungen_Fragment extends Fragment{


    //Elemente:
    private RecyclerView recyclerView_aktuelle_Bewertungen;


    private View aktuelleBewertungenView;

    private DatabaseReference essenRef;
    private DatabaseReference bewertungenRef;



    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        aktuelleBewertungenView =  inflater.inflate(R.layout.fragment_aktuelle_bewertungen, container, false);

        //Elemente finden:
        recyclerView_aktuelle_Bewertungen = (RecyclerView) aktuelleBewertungenView.findViewById(R.id.recyler_aktuelle_bewertungen);

        //Referenz auf essen:
        essenRef = FirebaseDatabase.getInstance().getReference().child("essen");
        //Referenz auf bewertungen:
        bewertungenRef = FirebaseDatabase.getInstance().getReference().child("bewertung");


        return aktuelleBewertungenView;
    }



    @Override
    public void onStart() {

        super.onStart();

        FirebaseRecyclerOptions options = new FirebaseRecyclerOptions.Builder<essen>().setQuery(essenRef, essen.class).build();
        final FirebaseRecyclerAdapter<essen, EssenViewHolder> adapter = new FirebaseRecyclerAdapter<essen, EssenViewHolder>(options) {

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

                View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.reihen, parent, false);
                EssenViewHolder viewHolder = new EssenViewHolder(view);

                return viewHolder;

            }

            @Override
            protected void onBindViewHolder(@NonNull final EssenViewHolder holder, final int position, @NonNull essen model) {


                final ArrayList<essen> testessen =new ArrayList<>();

                essenRef.addValueEventListener(new ValueEventListener() {

                    @Override
                    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                        for (DataSnapshot ds : dataSnapshot.getChildren()){

                                final essen e = new essen();
                                  e.name =   ds.child("name").getValue(String.class);
                                  e.Preis = ds.child("Preis").getValue(String.class);


                            bewertungenRef.addValueEventListener(new ValueEventListener() {
                                @Override
                                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                                    float sum = (float) 0.0;
                                    int counter = 0;


                                    for (DataSnapshot ds1 : dataSnapshot.getChildren()){
                                        if (ds1.child("eid").getValue(String.class).equals(e.name)){

                                            sum = sum + ds1.child("wert").getValue(float.class);
                                            counter ++;

                                        }
                                    }

                                    float durchschnitt = sum/counter;

                                    Log.i("durchschnitt" , " " + sum + " "+ counter + " " +durchschnitt);

                                    e.setAverage(durchschnitt);

                                    Log.i("essen wert: " , " " + e.getAverage());

                                }

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

                                }
                            });

                            testessen.add(e);

                        }


                        holder.essenName.setText(testessen.get(position).getName());
                        holder.essenPreis.setText(testessen.get(position).getPreis());

                        float test = (float) testessen.get(position).getAverage();
                        Log.i("test :" , " "+ test);
                        holder.test.setText(testessen.get(position).getAverage());

                    }

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

                    }
                });
            }
        };

        recyclerView_aktuelle_Bewertungen.setLayoutManager(new LinearLayoutManager(getContext()));
        recyclerView_aktuelle_Bewertungen.setAdapter(adapter);
        recyclerView_aktuelle_Bewertungen.hasFixedSize();
        adapter.startListening();
    }



    public  class EssenViewHolder extends RecyclerView.ViewHolder{

        TextView essenName, essenPreis, test;

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

            essenName = itemView.findViewById(R.id.reihen_name);
            essenPreis = itemView.findViewById(R.id.reihen_preis);

            test = itemView.findViewById(R.id.reihen_test);


        }


    }


}

平均计算的输出是:对于食物测试1:

I/durchschnitt:12.5 4 3.125 -> 12.5/4 = 3.125

对于测试2:

I/durchschnitt:12.5 4 3.125 -> 12.5/4 = 3.125

对于测试3:

I/durchschnitt:2.5 1 2.5 -> 2.5/1 = 2.5

数据库中的条目:Test1: 3 + 3+ 4 +2.5 = 12.5 test 2: 3.5+3.5+3+2.5= 12.5 test 3: 2.5 = 2.5 计算似乎工作得很好......

这是我的 essen 课程:

    String name,Preis;
    float average;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPreis() {
        return Preis;
    }

    public void setPreis(String preis) {
        Preis = preis;
    }

    public float getAverage() {
        return average;
    }

    public void setAverage(float average) {
        this.average = average;
    }


    public essen (String name, String Preis, float average){
        this.name = name;
        this.Preis = Preis;
        this.average = average;
    }

    public essen(){}

}

这是我的 XML 布局文件,它显示在回收站视图中(我删除了所有不必要的视图,因此约束可能看起来有点奇怪):

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="90dp"
        android:layout_margin="10dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">



            <TextView
                android:id="@+id/reihen_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:fontFamily="@font/roboto"
                android:text="Name"
                android:textColor="@color/rot"
                android:textSize="17sp"
                android:textStyle="bold"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.064"
                app:layout_constraintStart_toEndOf="@+id/reihen_bilder"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintVertical_bias="0.149" />

            <TextView
                android:id="@+id/reihen_preis"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:fontFamily="@font/roboto"
                android:text="Preis"
                android:textColor="@color/black"
                android:textSize="17sp"
                android:textStyle="normal"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.723"
                app:layout_constraintStart_toEndOf="@+id/reihen_bilder"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintVertical_bias="0.507" />



            <TextView
                android:id="@+id/reihen_test"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="TextView"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.552"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintVertical_bias="0.14" />


        </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>

这是我的 Firebase 数据库的屏幕截图:

【问题讨论】:

  • 代码乍一看还可以,但是对于这么多的代码,很难使用人工调试器。如果您在内部onDataChange 中放置一个断点并在调试器中运行代码,它会到达断点吗?如果是这样,当您从那里开始逐步执​​行代码时,每一行是否都符合您的预期? sum 是否按预期递增?如果是这样,durchschnitt 是否得到正确的值?
  • 是的,我在控制台的循环内显示了每个值(总和、计数器和平均值)(Log.i.... 在上面的代码中),根据数据库中的条目
  • 但不知何故我无法将我在那里计算的平均值设置为 essen(食物)对象
  • 虽然其他值(名称和价格)的设置方式相同,但对于这些值,一切正常
  • 所以听起来是e.setAverage(durchschnitt); 导致了问题。如果您在此处设置硬编码字符串 (e.setAverage("test");),它会显示吗?如果您将该语句移到数据加载之外,它会显示出来吗?

标签: android firebase-realtime-database arraylist pojo


【解决方案1】:

我现在看到您正在设置计算数据的 onDataChange 之外的视图的平均值。这行不通,因为当您的 holder.test.setText(testessen.get(position).getAverage()) 运行时,e.setAverage(durchschnitt) 还没有运行。

任何需要来自数据库的数据的代码都需要在该数据的onDataChange 中,或者从那里调用。

执行此操作的最简单方法是仅显示嵌套 onDataChange 内部的平均值:

final ArrayList<essen> testessen =new ArrayList<>();

essenRef.addValueEventListener(new ValueEventListener() {

    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

        for (DataSnapshot ds : dataSnapshot.getChildren()){

            final essen e = new essen();
            e.name  = ds.child("name").getValue(String.class);
            e.Preis = ds.child("Preis").getValue(String.class);

            bewertungenRef.addListenerForSingleValue(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                    float sum = (float) 0.0;
                    int counter = 0;


                    for (DataSnapshot ds1 : dataSnapshot.getChildren()){
                        if (ds1.child("eid").getValue(String.class).equals(e.name)){

                            sum = sum + ds1.child("wert").getValue(float.class);
                            counter ++;

                        }
                    }

                    float durchschnitt = sum/counter;

                    Log.i("durchschnitt" , " " + sum + " "+ counter + " " +durchschnitt);

                    e.setAverage(durchschnitt);

                    Log.i("essen wert: " , " " + e.getAverage());

                    holder.essenName.setText(testessen.get(position).getName());
                    holder.essenPreis.setText(testessen.get(position).getPreis());

                    float test = (float) testessen.get(position).getAverage();
                    Log.i("test :" , " "+ test);
                    holder.test.setText(testessen.get(position).getAverage());
                }

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {
                    throw databaseError.toException(); // don't ignore errors
                }
            });

            testessen.add(e);
        }
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        throw databaseError.toException(); // don't ignore errors
    }
});

在上面,您从bewertungenRef 加载所有数据,而您只需要这些项目的一个子集。您还为每次迭代重新加载该数据,这非常浪费(但应该可以)。

根据您拥有的数据量,您可能需要考虑仅从 bewertungenRef 加载所需的子节点。这意味着您有多个侦听器,这是一个很好的时机,也可以在加载完所有数据后才更新 UI 中的平均值。

看起来像这样(未经测试,因此代码可能包含小问题):

final ArrayList<essen> testessen =new ArrayList<>();

essenRef.addValueEventListener(new ValueEventListener() {

    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        float sum = (float) 0.0;
        int counter = 0;

        // these variables track how many items we need to load, and how many we've already loaded
        long essenCount = dataSnapshot.getChildrenCount();
        long loadedCount = 0;

        for (DataSnapshot ds : dataSnapshot.getChildren()){
            final essen e = new essen();
            e.name  = ds.child("name").getValue(String.class);
            e.Preis = ds.child("Preis").getValue(String.class);

            bewertungenRef.orderByChild("eid").equalTo(e.name).addListenerForSingleValue(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    for (DataSnapshot ds1 : dataSnapshot.getChildren()){
                        sum = sum + ds1.child("wert").getValue(float.class);
                        counter++;
                    }

                    if (loadedCount++ == essenCont) {
                        float durchschnitt = sum/counter;

                        e.setAverage(durchschnitt);

                        Log.i("essen wert: " , " " + e.getAverage());

                        holder.essenName.setText(testessen.get(position).getName());
                        holder.essenPreis.setText(testessen.get(position).getPreis());

                        holder.test.setText(testessen.get(position).getAverage());
                    }
                }

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {
                    throw databaseError.toException(); // don't ignore errors
                }
            });

            testessen.add(e);
        }
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        throw databaseError.toException(); // don't ignore errors
    }
});

【讨论】:

  • 非常感谢!!您的第一个解决方案效果很好!!!我也尝试过第二个,但是我的 Viewholders 没有填充数据,它们只是显示 XML“默认”布局......但是你的第一个解决方案应该足以满足我的需要:P
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-28
  • 2011-03-14
  • 1970-01-01
  • 1970-01-01
  • 2011-06-23
  • 1970-01-01
相关资源
最近更新 更多