我尝试实施动作模式以删除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来重建索引,但没有效果。
答案 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();
}