具有操作模式的FirebaseRecyclerAdapter可删除项目

时间:2016-08-01 13:04:17

标签: android firebase-realtime-database firebaseui

我尝试实施动作模式以删除FirebaseRecyclerView中的项目。奇怪的是,有时删除的项目不是所选项目。我认为错误在ToogleSelection方法或RemoveItems方法中,但我不知道它是什么。

适配器代码:

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

修改

在我看来,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来重建索引,但没有效果。

1 个答案:

答案 0 :(得分: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();
}