0

내 응용 프로그램에는 ListView를 통해 식물과 그 수량 (Firebase에 저장 됨)을 표시하려는 섹션 (조각)이 있습니다. 플로팅 액션 버튼을 사용하여 플랜트와 관련된 수량을 이미 db에있는 경우 업데이트 할 수 있습니다. 그렇지 않은 경우 추가 할 수 있습니다. 여기Firebase를 사용하는 ListView 및 사용자 지정 어댑터

처음 두 가지 문제 :

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

은 음 ... 데이터베이스는 항상 제대로 업데이트되지만 : 식물이 두 번 나타나도록 때때로 plantsList 및 quantityLists이 복제본을 삽입 또는 3 배로 나는 그것을 원하지 않는다.

편집 : 이러한 두 가지 문제를 해결하는 데 성공했습니다. 이제 다음과 같은 문제가 있습니다. 종종이 오류가 발생합니다

10-19 19 : 28 : 52.460 19148-19148/.veggarden E/AndroidRuntime : 치명적인 예외를 : 주요 프로세스 : .veggarden, PID : 19148 java.lang.NullPointerException이를 :. .veggarden.MyVegGardenAdapter에서 널 오브젝트 참조 에 'java.lang.Object 상위 android.content.Context.getSystemService (java.lang.String의)'의 가상 메소드를 호출 시도 (MyVegGardenAdapter.java:31) at .veggarden.MyVegGardenFragment $ 1.onDataChange (MyVegGardenFragment.java:85) com.google.android.gms.internal.zzbmz.zza (알 수없는 출처) com.google.android.gms.internal.zzbnz.zzYj (알 수없는 출처) at com.google.android.gms.internal.zzboc의 $의 1.run (알 수없는 소스) android.os.Handler.handleCallback (Handler.java:751) android.os.Handler.dispatchMessage에서 (Handler.java:95)에서 01,235,164에서 java.lang.reflect.Method.invoke (기본 방법) 에서 android.app.ActivityThread.main (ActivityThread.java:6077) 에서 android.os.Looper.loop (Looper.java:154) 에서 com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:866) com.android.internal.os.ZygoteInit.main에서 (ZygoteInit.자바 : 756)

지금까지이 오류가 발생합니다

  1. 처음으로 내가 컨텍스트가 null는 아니고,하지만를 추가 한 후 (DB에서 내 공장을 삭제할 때 나는 식물을 추가하려고 식물은 식물
  2. 거의 그렇게 확실하지) (많은 식물을 추가하지
012을 추가
  • 내가 바닥 도구 모음을 통해 다른 조각에 갈 때 나는이 단편에 돌아와)입니다 여기 3,516,

    내 - - 날짜 코드 :

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

    어댑터 이전과 동일합니다.

    누군가가 나를 도울 수 있기를 바랍니다.

  • +0

    나는 또한 당신 덕분에 내 문제를 해결했습니다. 가능한 한 한 가지만 남겨주세요. 감사하게 생각합니다. – Benny

    답변

    1

    데이터 검색은 중포 기지에서 비동기, 그래서 당신의 목록을 즉시 작성되지 않습니다. 데이터가 검색 될 때까지 ProgressBar 또는 "Loading ..."과 비슷한 텍스트가있는 간단한 TextView를 표시하는 것을 고려할 수 있습니다.

    또한, 당신은 addValueEventListener() 제공 리스너 때마다 데이터가 변경이라고합니다.

    두 번째 문제는 두 가지 조정해야한다고 생각합니다. 첫 번째 onCreateView()에서 최고의 addValueEventListener()를 업데이트 :

    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를 업데이트합니다.

    +0

    나는 데이터베이스 콜백에 어댑터를 넣는 첫 번째 문제를 해결했지만, 두 번째 문제는 당신의 아이디어에서부터 풀어 냈습니다. 마지막 문제로 게시물을 업데이트했습니다. 가능하면 도와 주시고 감사드립니다! – Benny

    +0

    어댑터의 31 번째 라인은 어느 라인입니까? – Mehmed

    +0

    죄송합니다. 편집했습니다. 어쨌든 : inflater = (LayoutInflater) this.context.getSystemService (Context.LAYOUT_INFLATER_SERVICE); – Benny

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

    을, 나는 plantList 또는 quantityList 전에 어댑터를 설정하는 당신이 개인의 ArrayList를 채울 경우 표시되지 않는 이유는 무엇입니까?

    +0

    firebase에서 해시 맵을 추출한 다음 plantsList 및 quantityList를 키와 값으로 채 웁니다. 코드에서이 부분을 찾을 수 있습니다에 대한 을 (의 Map.Entry <문자열, 정수> 항목 : myVegGarden.entrySet()) { plantsList.add (entry.getKey()); quantityList.add (entry.getValue()); – Benny

    +0

    네,하지만 어댑터를 설정하기 전에 그렇게하지는 않습니다. 당신은 이전에 추가/업데이트 한 후에 그것을합니다. – Barns

    +0

    네 말이 맞아, 내 첫 번째 문제는 그것에 의해 야기되었다. 고마워! – Benny

    관련 문제