0

In meiner Anwendung habe ich einen Abschnitt (Fragment), wo ich die Pflanzen und ihre Mengen (in Firebase gespeichert) durch eine ListView zeigen möchte. Mit einem Floating-Aktion-Button erlaube ich, die Menge zu aktualisieren, die sich auf eine Pflanze bezieht, wenn sie bereits in der Datenbank ist, andernfalls, um sie hinzuzufügen.ListView und benutzerdefinierter Adapter mit Firebase

Hier meine ersten zwei Probleme:

# 1 Dieses Fragment wird in der Haupt-Aktivität gezeigt, so beim Start Ich mag würde, dass die aus der Datenbank abgerufenen Daten werden sofort angezeigt, aber das doesn‘ t geschehen, sie werden nur angezeigt, nachdem eine Anlage hinzugefügt/aktualisiert wurde.

# 2 Hier ist mein Code:

public class MyVegGardenFragment extends Fragment { 

    private View v; 
    private ListView listView; 
    private DatabaseReference database; 
    private FirebaseAuth auth; 
    private FirebaseUser us; 
    private Map<String, Integer> myVegGarden; 
    private ArrayList<String> plantsList = new ArrayList<>(); 
    private ArrayList<Integer> quantityList = new ArrayList<>(); 
    private MyVegGardenAdapter adapter; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 


     myVegGarden = new HashMap<>(); 

     database = FirebaseDatabase.getInstance().getReference(); 
     auth = FirebaseAuth.getInstance(); 
     us = auth.getCurrentUser(); 

     database.addValueEventListener(new ValueEventListener() { 
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 
      @Override 
      public void onDataChange(DataSnapshot dataSnapshot) { 

       User u = dataSnapshot.child("users").child(us.getUid()).getValue(User.class); 
       if (u != null) { 
        myVegGarden = u.getMyVegGarden(); 
        if (myVegGarden != null) { 
         for(Map.Entry<String, Integer> entry : myVegGarden.entrySet()) { 
          plantsList.add(entry.getKey()); 
          quantityList.add(entry.getValue()); 
         } 
        } 
       } 
      } 

      @Override 
      public void onCancelled(DatabaseError databaseError) { 
      } 
     }); 


     v = inflater.inflate(R.layout.myveggarden_fragment_layout, container, false); 
     listView = (ListView) v.findViewById(R.id.myVegGarden_list_view); 
     adapter = new MyVegGardenAdapter(getActivity(), plantsList, quantityList); 
     listView.setAdapter(adapter); 

     FloatingActionButton fab = (FloatingActionButton) v.findViewById(R.id.fab); 
     fab.setOnClickListener(new View.OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       AlertDialog.Builder builder; 
       // [...] leaving code for AlertDialog working correctly 
       builder.setPositiveButton("PLANT", new DialogInterface.OnClickListener() { 
       public void onClick(DialogInterface dialog, int which) { 
         final String plant = options[plant_picker.getValue()]; 
         final int quantity = quantity_picker.getValue(); 


         if(!adapter.getPlantsList().contains(plant)){ 
          adapter.add(plant, quantity); 
         } 
         else { 
          adapter.updateIfPresent(plant, quantity); 
         } 

         //update db value 
         database.addValueEventListener(new ValueEventListener() { 
          @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 
          @Override 
          public void onDataChange(DataSnapshot dataSnapshot) { 

           User u = dataSnapshot.child("users").child(us.getUid()).getValue(User.class); 
           if (u != null) { 
            myVegGarden = u.getMyVegGarden(); 
            if (myVegGarden != null) { 
             myVegGarden.put(plant, quantity); 
            } 
            else { 
             myVegGarden = new HashMap<>(); 
             myVegGarden.put(plant, quantity); 
             } 
            database.child("users").child(us.getUid()).child("myVegGarden").setValue(myVegGarden); 
            } 
          } 

          @Override 
          public void onCancelled(DatabaseError databaseError) { 
          } 
         }); 
         dialog.dismiss(); 
         } 
       }); 

       builder.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() { 
        public void onClick(DialogInterface dialog, int which) { 
         dialog.dismiss(); 
        } }); 

       AlertDialog dialog = builder.create(); 
       dialog.show(); 
      } 
     }); 

     return v; 
    } 

} 
public class MyVegGardenAdapter extends BaseAdapter { 

    private Context context; 
    private LayoutInflater inflater; 
    private ArrayList<String> dataSource; 
    private ArrayList<Integer> quantity; 

    public MyVegGardenAdapter(Context context, ArrayList<String> items, ArrayList<Integer> quantity) { 
     this.context = context; 
     dataSource = items; 
     this.quantity = quantity; 
     //line 31 
     inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    } 

    public void add(String plant, Integer qty) { 
     dataSource.add(plant); 
     quantity.add(qty); 
     notifyDataSetChanged(); 
    } 

    public void updateIfPresent(String plant, Integer qty) { 
     quantity.set(dataSource.indexOf(plant), qty); 
     notifyDataSetChanged(); 
    } 

    public List<String> getPlantsList() { return dataSource; } 

    @Override 
    public int getCount() { 
     return dataSource.size(); 
    } 

    @Override 
    public Object getItem(int position) { 
     return dataSource.get(position); 
    } 

    @Override 
    public long getItemId(int position) { 
     return position; 
    } 

    public Object getQuantity(int position) { 
     return quantity.get(position); 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     // Get view for row item 
     View rowView = inflater.inflate(R.layout.listview_row, parent, false); 

     // Get title element 
     TextView firstLine = (TextView) rowView.findViewById(R.id.firstLine); 
     // Get subtitle element 
     TextView secondLine = (TextView) rowView.findViewById(R.id.secondLine); 
     // Get icon element 
     ImageView icon = (ImageView) rowView.findViewById(R.id.list_icon); 

     String plant = (String) getItem(position); 
     Integer quantity = (Integer) getQuantity(position); 

     firstLine.setText(plant); 
     secondLine.setText(Html.fromHtml("<b>Quantity: </b>" + quantity)); 

     switch(plant) { 
      case "Bean": 
       icon.setImageResource(R.drawable.ic_bean_48dp); break; 
      case "Cabbage": 
       icon.setImageResource(R.drawable.ic_cabbage_48dp); break; 
      case "Carrot": 
       icon.setImageResource(R.drawable.ic_carrot_48dp); break; 
      case "Cucumber": 
       icon.setImageResource(R.drawable.ic_cucumber_48dp); break; 
      case "Eggplant": 
       icon.setImageResource(R.drawable.ic_eggplant_48dp); break; 
      case "Lettuce": 
       icon.setImageResource(R.drawable.ic_lettuce_48dp); break; 
      case "Pea": 
       icon.setImageResource(R.drawable.ic_pea_48dp); break; 
      case "Pepper": 
       icon.setImageResource(R.drawable.ic_pepper_48dp); break; 
      case "Radish": 
       icon.setImageResource(R.drawable.ic_radish_48dp); break; 
      case "Tomato": 
       icon.setImageResource(R.drawable.ic_tomato_48dp); break; 
     } 
     return rowView; 
    } 
} 

Nun ... ist die Datenbank immer korrekt aktualisiert, aber: manchmal plantsList und quantityLists Repliken einfügen, so Pflanzen zweimal erscheinen oder dreimal und ich will es nicht.

EDIT: Ich gelang es, diese beiden Probleme zu lösen. Jetzt gibt es nur das folgende Problem. Sehr oft tritt dieser Fehler auf:

10-19 19: 28: 19.148 bis 19.148 52,460/.veggarden E/Android Runtime: fatal EXCEPTION: main Prozess: .veggarden, PID: 19148 java.lang.NullPointerException :. Attempt virtuelle Methode 'java.lang.Object android.content.Context.getSystemService (java.lang.String)' auf null Objektreferenz bei .veggarden.MyVegGardenAdapter (MyVegGardenAdapter.java:31) aufzurufen um .veggarden.MyVegGardenFragment $ 1.onDataChange (MyVegGardenFragment.java:85) bei com.google.android.gms.internal.zzbmz.zza (Unbekannte Quelle) bei com.google.android.gms.internal.zzbnz.zzYj (unbekannte Quelle) bei com.google.android.gms.internal.zzboc $ 1.run (Unbekannte Quelle) bei android.os.Handler.handleCallback (Handler.java:751) bei android.os.Handler.dispatchMessage (Handler.java:95) bei android.os.Looper.loop (Looper.java:154) bei android.app.ActivityThread.main (ActivityThread.java:6077) bei java.lang.reflect.Method.invoke (native Methode) bei 01.235.com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:866) bei com.android.internal.os.ZygoteInit.main (ZygoteInit.java: 756)

Bis jetzt dieser Fehler auftritt:

  1. das erste Mal ich versuche, eine Anlage hinzufügen, wenn ich meine Anlage von db gelöscht (im Kontext nicht null ist, aber nach einer Zugabe Pflanze es ist)
  2. , wenn ich zu einem anderen Fragment durch eine untere Symbolleiste gehen und dann an dieses Fragment ich wieder eine Pflanze
  3. beim hinzufügen von vielen Pflanzen (selten und nicht so sicher)
012 hinzufügen

Hier mein up-to-date-Code:

public class MyVegGardenFragment extends Fragment { 

    private View v; 
    private ListView listView; 
    private DatabaseReference database; 
    private FirebaseAuth auth; 
    private FirebaseUser us; 
    private Map<String, Integer> myVegGarden; 
    private ArrayList<String> plantsList = new ArrayList<>(); 
    private ArrayList<Integer> quantityList = new ArrayList<>(); 
    private MyVegGardenAdapter adapter; 


    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 


     myVegGarden = new HashMap<>(); 

     database = FirebaseDatabase.getInstance().getReference(); 
     auth = FirebaseAuth.getInstance(); 
     us = auth.getCurrentUser(); 

     v = inflater.inflate(R.layout.myveggarden_fragment_layout, container, false); 
     listView = (ListView) v.findViewById(R.id.myVegGarden_list_view); 

     database.addValueEventListener(new ValueEventListener() { 
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 
      @Override 
      public void onDataChange(DataSnapshot dataSnapshot) { 

       plantsList = new ArrayList<String>(); 
       quantityList = new ArrayList<Integer>(); 

       User u = dataSnapshot.child("users").child(us.getUid()).getValue(User.class); 
       if (u != null) { 
        myVegGarden = u.getMyVegGarden(); 
        if (myVegGarden != null) { 
         for(Map.Entry<String, Integer> entry : myVegGarden.entrySet()) { 
          plantsList.add(entry.getKey()); 
          quantityList.add(entry.getValue()); 
         } 
        } 
        **line 85** 
        adapter = new MyVegGardenAdapter(getActivity(), plantsList, quantityList); 
        listView.setAdapter(adapter); 
       } 
      } 

      @Override 
      public void onCancelled(DatabaseError databaseError) { 
      } 
     }); 


     FloatingActionButton fab = (FloatingActionButton) v.findViewById(R.id.fab); 
     fab.setOnClickListener(new View.OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       AlertDialog.Builder builder; 
       // [...] leaving code for AlertDialog working correctly 
       builder.setPositiveButton("PLANT", new DialogInterface.OnClickListener() { 
        public void onClick(DialogInterface dialog, int which) { 
         final String plant = options[plant_picker.getValue()]; 
         final int quantity = quantity_picker.getValue(); 

         if(!adapter.getPlantsList().contains(plant)){ 
          adapter.add(plant, quantity); 
         } 
         else { 
          adapter.updateIfPresent(plant, quantity); 
         } 

         if (myVegGarden != null) { 
          myVegGarden.put(plant, quantity); 
          database.child("users").child(us.getUid()).child("myVegGarden").setValue(myVegGarden); 
         } 

         else { 
          myVegGarden = new HashMap<String, Integer>(); 
          myVegGarden.put(plant, quantity); 
          database.child("users").child(us.getUid()).child("myVegGarden").setValue(myVegGarden); 
         } 

         dialog.dismiss(); 
        } 
       }); 

       builder.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() { 
        public void onClick(DialogInterface dialog, int which) { 
         dialog.dismiss(); 
        } }); 

       AlertDialog dialog = builder.create(); 
       dialog.show(); 
      } 
     }); 

     return v; 
    } 

Der Adapter ist das gleiche wie zuvor.

Ich hoffe, dass mir jemand helfen kann.

+0

Ich löste meine Probleme auch dank dir. Jetzt gibt es nur noch ein Problem, bitte schauen Sie, wenn Sie können, ich werde es zu schätzen wissen. – Benny

Antwort

1

Datenabruf ist in Firebase asynchron, daher wird Ihre Liste nicht sofort ausgefüllt. Sie können eine ProgressBar oder eine einfache TextView mit einem ähnlichen Text wie "Loading ..." anzeigen, bis die Daten abgerufen werden.

Auch der Listener, den Sie addValueEventListener() zur Verfügung gestellt haben, wird jedes Mal aufgerufen, wenn sich die Daten ändern.

Für das zweite Problem, ich denke, Sie sollten zwei Tweaks tun. Erste ist die Aktualisierung der oben addValueEventListener() in onCreateView():

database.addValueEventListener(new ValueEventListener() { 
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 
      @Override 
      public void onDataChange(DataSnapshot dataSnapshot) { 

       User u = dataSnapshot.child("users").child(us.getUid()).getValue(User.class); 
       if (u != null) { 
        myVegGarden = u.getMyVegGarden(); 
        if (myVegGarden != null) { 
         plantsList = new ArrayList<>(); 
         quantityList = new ArrayList<>(); 
         for(Map.Entry<String, Integer> entry : myVegGarden.entrySet()) { 
          plantsList.add(entry.getKey()); 
          quantityList.add(entry.getValue()); 
         } 
         adapter.notifyDataSetChanged(); 
        } 
       } 
      } 

      @Override 
      public void onCancelled(DatabaseError databaseError) { 
      } 
     }); 

Zweite Tweak ist Alertdialog des onClick() wie folgt zu vereinfachen: ausreichen

@Override 
public void onClick(DialogInterface dialog, int which) { 
    final String plant = options[plant_picker.getValue()]; 
    final int quantity = quantity_picker.getValue(); 

    // Update db value 
    myVegGarden = new HashMap<>(); 
    myVegGarden.put(plant, quantity); 
    database.child("users").child(us.getUid()).child("myVegGarden").setValue(myVegGarden); 
} 

Dies sollte. Erstellen Sie eine Karte mit der Anlage und der Menge, und setValue() fügt sie dem Pfad hinzu, wenn dieses Paar dort nicht existiert. Wenn das Paar in diesem Pfad vorhanden ist, aktualisiert setValue() es. Dieses Update ruft wiederum die optimierte addValueEventListener(), PlantList und QuantityList aktualisieren.

+0

Ich löste das erste Problem, indem ich den Adapter in den Datenbank-Callback setzte, während ich den zweiten von Ihrer Idee ausgehend löste. Ich habe meinen Beitrag mit meinem letzten Problem aktualisiert, bitte schauen Sie, ob Sie es können und danke für Ihre Hilfe! – Benny

+0

Welche Zeile ist die 31. Zeile im Adapter? – Mehmed

+0

Sorry, ich habe bearbeitet. Wie auch immer es ist: inflater = (LayoutInflater) this.context.getSystemService (Context.LAYOUT_INFLATER_SERVICE); – Benny

0

Dies ist eher eine Frage an Ihren Code als eine Antwort. (Es ist einfacher, hier Code hinzuzufügen).

In Ihrer onCreateView Methode Sie haben dies:

v = inflater.inflate(R.layout.myveggarden_fragment_layout, container, false); 
     listView = (ListView) v.findViewById(R.id.myVegGarden_list_view); 
     adapter = new MyVegGardenAdapter(getActivity(), plantsList, quantityList); 
     listView.setAdapter(adapter); 

Aber ich sehe nicht, wo Sie die einzelne Arraylist füllen plantList oder quantityList vor dem Adapter auf Einstellung?

+0

Ich extrahiere die hashmap aus Firebase und fülle dann PflanzenList und QuantityList mit Schlüsseln und Werten. Im Code finden Sie diesen Teil: für (Map.Entry -Eintrag: myVegGarden.entrySet()) { plantList.add (entry.getKey()); mengenliste.add (entry.getValue()); – Benny

+0

ja, aber ich sehe nicht, dass Sie das tun, bevor Sie den Adapter einstellen. Sie tun es nach dem Hinzufügen/Aktualisieren, aber nicht vorher. – Barns

+0

Du hast recht, mein erstes Problem wurde dadurch verursacht, danke! – Benny

Verwandte Themen