2016-08-01 14 views
2

Ich versuche, einen Aktionsmodus zum Löschen von Elementen in FirebaseRecyclerView zu implementieren. Das Seltsame ist, dass manchmal die gelöschten Objekte nicht die ausgewählten Objekte sind. Ich denke, dass der Fehler in ToogleSelection-Methode oder RemoveItems-Methode ist, aber ich weiß nicht, was es ist.FirebaseRecyclerAdapter mit Aktionsmodus zum Löschen von Elementen

Der Adapter Code:

public class NewsAdapter extends FirebaseRecyclerAdapter<Noticia, NoticiasViewHolder> { 

    private int color; 
    private int selectedColor; 
    private NoticiasFragment fragment; 
    private final Globals globals; 
    private ActionMode actionMode; 
    private final SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy"); 
    private SparseIntArray selectedItems = new SparseIntArray(); 

    public NewsAdapter(NoticiasFragment fragment, Query ref) { 

     super(Noticia.class, R.layout.list_item_noticia, NoticiasViewHolder.class, ref); 
     this.color = ContextCompat.getColor(fragment.getActivity(), R.color.background_card); 
     this.selectedColor = ContextCompat.getColor(fragment.getActivity(), R.color.background_selected); 
     this.globals = (Globals) fragment.getActivity().getApplicationContext(); 
     this.fragment = fragment; 
    } 


    @Override 
    protected void populateViewHolder(NoticiasViewHolder viewHolder, final Noticia model, final int position) { 

     viewHolder.imageView.setImageUrl(model.linkImg, globals.getImageLoader()); 
     viewHolder.bindToNoticia(fragment.getActivity(), model, dateFormat); 

     final DatabaseReference noticiaRef = getRef(position); 

     viewHolder.itemView.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 

       if (getSelectedItemCount()>0) { 

        if (toggleSelection(position)) { 
         v.setBackgroundColor(selectedColor); 

        } else { 
         v.setBackgroundColor(color); 
         if (getSelectedItemCount()==0 && actionMode!=null) { 
          actionMode.finish(); 
         } 
        } 
        return; 
       } 

       if (!Server.isOnline(fragment.getActivity(), R.string.sem_conexao_noticia)) 
        return; 

       Intent i = new Intent(fragment.getActivity(), NewsActivity.class); 
       i.putExtra("Noticia", model); 
       fragment.startActivity(i); 
      } 
     }); 

     viewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() { 

      @Override 
      public boolean onLongClick(View v) { 

       if (toggleSelection(position)) { 
        v.setBackgroundColor(selectedColor); 

        if (actionMode != null) 
         return true; 
        Toolbar toolbar = (Toolbar) fragment.getActivity().findViewById(R.id.toolbar); 
        actionMode = toolbar.startActionMode(mActionModeCallback); 
        actionMode.setTitle("1 selecionado"); 

       } else { 
        v.setBackgroundColor(color); 
        if (getSelectedItemCount() == 0 && actionMode != null) { 
         actionMode.finish(); 
        } 
       } 
       return true; 
      } 
     }); 

     if (selectedItems.get(position)!=0) 
      viewHolder.itemView.setBackgroundColor(selectedColor); 
     else viewHolder.itemView.setBackgroundColor(color); 

    } 


    /* Returns selected items count */ 
    public int getSelectedItemCount() { 
     return selectedItems.size(); 
    } 

    /* Select/unselect for deletion */ 
    public boolean toggleSelection(int position) { 
     boolean b; 
     if (selectedItems.get(position)!=0) { 
      selectedItems.delete(position); 
      b = false; 
     } 
     else { 
      selectedItems.put(position, position); 
      b = true; 
     } 
     int n = getSelectedItemCount(); 
     if (n>0 && actionMode!=null) { 
      actionMode.setTitle(String.valueOf(n) + (n==1 ? " selecionado" : " selecionados")); 
     } 
     return b; 
    } 

    /* Action to delete selected items */ 
    private void removeItems() { 

     String userId = fragment.getUid(); 

     while (selectedItems.size()>0) { 

      int position = selectedItems.keyAt(0); 
      DatabaseReference noticiaRef = getRef(position); 
      fragment.mDatabase.child("user-news").child(userId).child(noticiaRef.getKey()).removeValue(); 
      selectedItems.removeAt(0); 
     } 
    } 

    private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() { 

     @Override 
     public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { 

      MenuInflater inflater = actionMode.getMenuInflater(); 
      inflater.inflate(R.menu.menu_delete_noticias, menu); 

      Toolbar toolbar = (Toolbar) fragment.getActivity().findViewById(R.id.toolbar); 
      toolbar.setBackgroundColor(ContextCompat.getColor(fragment.getActivity(), R.color.accent2)); 

      TabLayout tabLayout = (TabLayout) fragment.getActivity().findViewById(R.id.sliding_tabs); 
      tabLayout.setBackgroundColor(ContextCompat.getColor(fragment.getActivity(), R.color.accent2)); 

      final Globals globals = (Globals) fragment.getActivity().getApplicationContext(); 
      globals.isInActionMode = true; 

      ((MainActivity) fragment.getActivity()).updatePage(0); 

      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
       Window window = (fragment.getActivity()).getWindow(); 
       window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 
       window.setStatusBarColor(ContextCompat.getColor(fragment.getActivity(), R.color.accent3)); 
      } 

      return true; 
     } 

     @Override 
     public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { 
      return false; 
     } 

     @Override 
     public boolean onActionItemClicked(final ActionMode actionMode, MenuItem menuItem) { 

      switch (menuItem.getItemId()) { 

       case R.id.menu_main_delete_noticias: 

        new SweetAlertDialog(fragment.getContext(), SweetAlertDialog.WARNING_TYPE) 
          .setTitleText(fragment.getResources().getString(R.string.excluir_noticias)) 
          .setContentText(fragment.getResources().getString(R.string.excluir_noticias_message)) 
          .setCancelText(fragment.getResources().getString(R.string.btn_nao_excluir)) 
          .setConfirmText(fragment.getResources().getString(R.string.btn_sim_excluir)) 
          .showCancelButton(true) 
          .setCancelClickListener(new SweetAlertDialog.OnSweetClickListener() { 
           @Override 
           public void onClick(SweetAlertDialog sDialog) { 
            actionMode.finish(); 
            sDialog.cancel(); 
           } 
          }) 
          .setConfirmClickListener(new SweetAlertDialog.OnSweetClickListener() { 
           @Override 
           public void onClick(SweetAlertDialog sDialog) { 

            /* Execute deletion */ 
            removeItems(); 

            actionMode.finish(); 
            sDialog 
              .setTitleText(fragment.getResources().getString(R.string.noticias_excluidas)) 
              .setContentText(fragment.getResources().getString(R.string.noticias_excluidas_message)) 
              .setConfirmText(fragment.getResources().getString(R.string.btn_ok)) 
              .showCancelButton(false) 
              .setConfirmClickListener(null) 
              .changeAlertType(SweetAlertDialog.SUCCESS_TYPE); 
           } 
          }) 
          .show(); 
        return true; 
       default: 
        return false; 
      } 
     } 

     @Override 
     public void onDestroyActionMode(ActionMode aMode) { 

      fragment.getActivity().findViewById(R.id.action_mode_bar).setVisibility(View.INVISIBLE); 

      Toolbar toolbar = (Toolbar) fragment.getActivity().findViewById(R.id.toolbar); 
      toolbar.setBackgroundColor(ContextCompat.getColor(fragment.getActivity(), R.color.primary)); 

      TabLayout tabLayout = (TabLayout) fragment.getActivity().findViewById(R.id.sliding_tabs); 
      tabLayout.setBackgroundColor(ContextCompat.getColor(fragment.getActivity(), R.color.primary)); 

      final Globals globals = (Globals) fragment.getActivity().getApplicationContext(); 
      globals.isInActionMode = false; 

      ((MainActivity) fragment.getActivity()).selectPage(3); 

      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
       Window window = fragment.getActivity().getWindow(); 
       window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 
       window.setStatusBarColor(ContextCompat.getColor(fragment.getActivity(), R.color.primaryDark)); 
      } 
      selectedItems.clear(); 
      notifyDataSetChanged(); 
      actionMode = null; 
     } 
    }; 
} 

EDIT:

mir scheint, dass die Indexpositionen von FirebaseRecyclerView nicht sofort nach dem remotions aktualisiert. Ich erkannte, dass, wenn ich 20 Produkte haben und die ersten 15 Elemente löschen, und wenn ich versuche, die neue erste zu löschen, erhalte ich folgende Fehlermeldung:

08-01 21:12:35.816 10747-10747/com.doeal.doeal E/AndroidRuntime: FATAL EXCEPTION: main 
                  Process: com.doeal.doeal, PID: 10747 
                  java.lang.IndexOutOfBoundsException: Invalid index 15, size is 5 
                   at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255) 
                   at java.util.ArrayList.get(ArrayList.java:308) 
                   at com.firebase.ui.database.FirebaseArray.getItem(FirebaseArray.java:52) 
                   at com.firebase.ui.database.FirebaseRecyclerAdapter.getRef(FirebaseRecyclerAdapter.java:150) 
                   at com.doeal.doeal.adapters.NoticiasAdapter.removeItems(NoticiasAdapter.java:187) 
                   at com.doeal.doeal.adapters.NoticiasAdapter.access$700(NoticiasAdapter.java:43) 
                   at com.doeal.doeal.adapters.NoticiasAdapter$4$1.onClick(NoticiasAdapter.java:248) 
                   at cn.pedant.SweetAlert.SweetAlertDialog.onClick(SweetAlertDialog.java:372) 
                   at android.view.View.performClick(View.java:5201) 
                   at android.view.View$PerformClick.run(View.java:21163) 
                   at android.os.Handler.handleCallback(Handler.java:746) 
                   at android.os.Handler.dispatchMessage(Handler.java:95) 
                   at android.os.Looper.loop(Looper.java:148) 
                   at android.app.ActivityThread.main(ActivityThread.java:5443) 
                   at java.lang.reflect.Method.invoke(Native Method) 
                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728) 
                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) 

ich NotifyDatasetChanged versucht ausführen, die Indizes neu zu erstellen, hat aber keine Wirkung.

Antwort

0

Ich fand das Problem, das ist mein Fehler. In der PopulateViewHolder-Methode übergab ich die int-Position anstelle des Referenzschlüssels an die Ereignisse OnClickListener und OnLongClickListener. Je mehr relevante Änderungen sind:

private Map<String, String> selectedItems = new HashMap<>(); 

...

viewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() { 
     @Override 
     public boolean onLongClick(View v) { 
      if (toggleSelection(noticiaRef.getKey())) { 
       v.setBackgroundColor(selectedColor); 

       if (actionMode != null) 
        return true; 
       Toolbar toolbar = (Toolbar) fragment.getActivity().findViewById(R.id.toolbar); 
       actionMode = toolbar.startActionMode(mActionModeCallback); 
       actionMode.setTitle("1 selecionado"); 
      } else { 
       v.setBackgroundColor(color); 
       if (getSelectedItemCount() == 0 && actionMode != null) { 
        actionMode.finish(); 
       } 
      } 
      return true; 
     } 
    }); 

...

public boolean toggleSelection(String key) { 
    boolean b; 
    if (selectedItems.get(key)!=null) { 
     selectedItems.remove(key); 
     b = false; 
    } 
    else { 
     selectedItems.put(key, key); 
     b = true; 
    } 
    int n = getSelectedItemCount(); 
    if (n>0 && actionMode!=null) { 
     actionMode.setTitle(String.valueOf(n) + (n==1 ? " selecionado" : " selecionados")); 
    } 
    return b; 
} 

private void removeItems() { 
    String userId = fragment.getUid(); 

    Iterator iterator = selectedItems.keySet().iterator(); 
    while(iterator.hasNext()) { 
     String key=(String) iterator.next(); 
     fragment.mDatabase.child("user-news").child(userId).child(key).removeValue(); 
    } 
    selectedItems.clear(); 
}