使用Firebase

时间:2017-10-18 22:51:19

标签: android listview android-fragments custom-adapter notifydatasetchanged

在我的应用程序中,我有一个部分(片段),我想通过ListView显示植物及其数量(存储在Firebase上)。 通过使用浮动操作按钮,我允许更新与工厂相关的数量(如果已经在数据库中),否则添加它。

这是我的前两个问题:

#1 这个片段显示在主要活动中,因此在启动时我希望立即显示从数据库中检索到的数据,但这并不会发生,只有在添加/更新工厂后才会显示它们。

#2 这是我的代码:

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;
    }
}

嗯......数据库总是正确更新,但是:有时plantList和quantityLists会插入副本,因此植物出现两次或三次,我不想要它。

修改 我成功地解决了这两个问题。 现在只有以下问题。通常会发生此错误:

  

10-19 19:28:52.460 19148-19148 / .veggarden   E / AndroidRuntime:致命异常:主要                                                                                         过程:.veggarden,PID:19148                                                                                         java.lang.NullPointerException:尝试调用虚方法   &#39; java.lang.Object中   android.content.Context.getSystemService(java.lang.String中)&#39;在null   对象参考                                                                                             在   .veggarden.MyVegGardenAdapter。(MyVegGardenAdapter.java:31)                                                                                             在   .veggarden.MyVegGardenFragment $ 1.onDataChange(MyVegGardenFragment.java:85)                                                                                             在com.google.android.gms.internal.zzbmz.zza(未知来源)                                                                                             在com.google.android.gms.internal.zzbnz.zzYj(未知来源)                                                                                             在com.google.android.gms.internal.zzboc $ 1.run(未知来源)                                                                                             在android.os.Handler.handleCallback(Handler.java:751)                                                                                             在android.os.Handler.dispatchMessage(Handler.java:95)                                                                                             在android.os.Looper.loop(Looper.java:154)                                                                                             在android.app.ActivityThread.main(ActivityThread.java:6077)                                                                                             at java.lang.reflect.Method.invoke(Native Method)                                                                                             在   com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:866)                                                                                             在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)

到目前为止,这个错误发生了:

  1. 第一次当我从db中删除我的植物时,我尝试添加植物(上下文不为null,但在添加植物之后)
  2. 当我通过底部工具栏转到另一个片段然后我回到此片段添加植物
  3. 添加许多植物(很少但不那么肯定)
  4. 这是我的最新代码:

    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;
        }
    

    适配器与以前相同。

    我希望有人可以帮助我。

2 个答案:

答案 0 :(得分:1)

数据检索在Firebase中是异步的,因此您的列表不会立即填充。在检索数据之前,您可以考虑使用类似于“正在加载...”的文本显示ProgressBar或简单TextView。

此外,每次数据更改时,都会调用您提供给addValueEventListener()的侦听器。

对于第二个问题,我认为你应该做两个调整。第一个是更新addValueEventListener()中的顶部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) {
            }
        });

第二个调整是简化AlertDialog的onClick(),如下所示:

@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);
}

这应该足够了。使用工厂和数量创建地图,setValue()将其添加到路径中(如果该对不存在)。如果该对存在于该路径中,setValue()将更新它。此更新将依次调用已调整的addValueEventListener(),更新plantList和quantityList。

答案 1 :(得分:0)

这对您的代码而言不仅仅是一个问题。 (这里更容易添加代码)。

onCreateView方法中,你有这个:

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);

但是,在设置适配器之前,我没有看到您填充单个ArrayList plantListquantityList的位置?