2016-08-01 88 views
2

我想實施一個操作模式來刪除FirebaseRecyclerView內的項目。奇怪的是,有時刪除的項目不是選定的項目。我認爲這個錯誤在ToogleSelection方法或RemoveItems方法中,但我不知道它是什麼。FirebaseRecyclerAdapter與行動模式刪除項目

適配器代碼:

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

編輯:

在我看來,是不是remotions後立刻更新從FirebaseRecyclerView索引位置。 我意識到,如果我有20個項目,並刪除第15個項目,如果我嘗試刪除新的第一次,我收到以下錯誤:

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) 

我試圖執行NotifyDatasetChanged重建索引,但沒有效果。

回答

0

我發現這個問題,那是我的錯誤。在PopulateViewHolder方法中,我將int位置而不是參考鍵傳遞給OnClickListener和OnLongClickListener事件。更相關的變化是:

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