在 recyclerview 片段中实现上下文操作模式的问题
Posted
技术标签:
【中文标题】在 recyclerview 片段中实现上下文操作模式的问题【英文标题】:Problems with implementing contextual action mode in recyclerview fragment 【发布时间】:2015-08-29 03:24:14 【问题描述】:我从一堆教程中破解了我的第一个应用程序。在其中一个的帮助下,我在主要活动使用的片段中实现了 RecyclerView。现在我找到了another tutorial,我想用它来实现上下文动作模式的多选。最大的问题是,本教程没有使用片段。我试图重写代码以适应片段。我现在在 android Studio 中没有任何错误并且应用程序运行,但是当我实际执行 LongClick 来选择一个项目时,它会崩溃并出现 NullPointerException:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.view.ActionMode.setTitle(java.lang.CharSequence)' on a null object reference
我完全不知道为什么会发生这种情况以及整个多选的东西。
我认为每个涉及的类的相关部分是:
Adapter.java:
public class Adapter extends SelectableAdapter<Adapter.ViewHolder>
private ArrayList<Meal> items = new ArrayList<>();
private Context context;
private ViewHolder.ClickListener clickListener;
public Adapter(ViewHolder.ClickListener clickListener)
super();
this.clickListener = clickListener;
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_today_items, parent, false);
return new ViewHolder(v, clickListener);
@Override
public void onBindViewHolder(final ViewHolder holder, int position)
Meal currentMeal = items.get(position);
holder.meal_typeicon.setImageResource(currentMeal.getBadgeIcon());
holder.meal_price.setText(currentMeal.getPriceOutput());
holder.meal_name.setText(isSelected(position) ? "SELECTED" : "NOT SELECTED");
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener
@SuppressWarnings("unused")
private static final String TAG = ViewHolder.class.getSimpleName();
private RelativeLayout meal_item;
private ClickListener listener;
private TextView meal_name;
private TextView meal_price;
private TextView meal_contents;
private TextView meal_contents_spelledout;
private ImageView meal_typeicon;
public ViewHolder(View itemView, ClickListener listener)
super(itemView);
meal_item = (RelativeLayout) itemView.findViewById(R.id.meal_item);
this.listener = listener;
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
meal_name = (TextView) itemView.findViewById(R.id.meal_name);
meal_price = (TextView) itemView.findViewById(R.id.meal_price);
meal_contents = (TextView) itemView.findViewById(R.id.meal_contents);
meal_contents_spelledout = (TextView) itemView.findViewById(R.id.meal_contents_spelledout);
meal_typeicon = (ImageView) itemView.findViewById(R.id.meal_typeicon);
@Override
public void onClick(View v)
if (listener != null)
listener.onItemClicked(getAdapterPosition());
@Override
public boolean onLongClick(View v)
if (listener != null)
return listener.onItemLongClicked(getAdapterPosition());
return false;
public interface ClickListener
void onItemClicked(int position);
boolean onItemLongClicked(int position);
@Override
public int getItemCount()
return items.size();
public void setMealList(ArrayList<Meal> listMeals)
this.items = listMeals;
notifyDataSetChanged();
notifyItemRangeChanged(0, listMeals.size());
SelectableAdapter.java:
public abstract class SelectableAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH>
@SuppressWarnings("unused")
private static final String TAG = SelectableAdapter.class.getSimpleName();
private SparseBooleanArray selectedItems;
public SelectableAdapter()
selectedItems = new SparseBooleanArray();
/**
* Indicates if the item at position position is selected
* @param position Position of the item to check
* @return true if the item is selected, false otherwise
*/
public boolean isSelected(int position)
return getSelectedItems().contains(position);
/**
* Toggle the selection status of the item at a given position
* @param position Position of the item to toggle the selection status for
*/
public void toggleSelection(int position)
if (selectedItems.get(position, false))
selectedItems.delete(position);
else
selectedItems.put(position, true);
notifyItemChanged(position);
/**
* Clear the selection status for all items
*/
public void clearSelection()
List<Integer> selection = getSelectedItems();
selectedItems.clear();
for (Integer i : selection)
notifyItemChanged(i);
/**
* Count the selected items
* @return Selected items count
*/
public int getSelectedItemCount()
return selectedItems.size();
/**
* Indicates the list of selected items
* @return List of selected items ids
*/
public List<Integer> getSelectedItems()
List<Integer> items = new ArrayList<>(selectedItems.size());
for (int i = 0; i < selectedItems.size(); ++i)
items.add(selectedItems.keyAt(i));
return items;
FragmentToday.java:
public class FragmentToday extends Fragment implements Adapter.ViewHolder.ClickListener
private RequestQueue requestQueue;
public ArrayList<Meal> listMeals = new ArrayList<>();
private TextView textVolleyError;
private MealSorter mSorter = new MealSorter();
private Adapter adapter;
private ActionModeCallback actionModeCallback = new ActionModeCallback();
private ActionMode actionMode;
public static FragmentToday newInstance()
return new FragmentToday();
public FragmentToday()
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
VolleySingleton volleySingleton = VolleySingleton.getInstance();
requestQueue = volleySingleton.getRequestQueue();
sendJsonRequest();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
View view = inflater.inflate(R.layout.fragment_today, container, false);
textVolleyError = (TextView) view.findViewById(R.id.textVolleyError);
adapter = new Adapter(this);
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
recyclerView.setAdapter(adapter);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
sendJsonRequest();
return view;
@Override
public void onItemClicked(int position)
if (actionMode != null)
toggleSelection(position);
@Override
public boolean onItemLongClicked(int position)
if (actionMode != null)
((AppCompatActivity) getActivity()).startSupportActionMode(actionModeCallback);
toggleSelection(position);
return true;
private void toggleSelection(int position)
adapter.toggleSelection(position);
int count = adapter.getSelectedItemCount();
if (count == 0)
actionMode.finish();
else
actionMode.setTitle(String.valueOf(count));
actionMode.invalidate();
private class ActionModeCallback implements ActionMode.Callback
@SuppressWarnings("unused")
private final String TAG = ActionModeCallback.class.getSimpleName();
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu)
mode.getMenuInflater().inflate (R.menu.menu_cam, menu);
return true;
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu)
return false;
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item)
switch (item.getItemId())
case R.id.favorite:
// TODO: actually remove items
Log.d(TAG, "menu_remove");
mode.finish();
return true;
default:
return false;
@Override
public void onDestroyActionMode(ActionMode mode)
adapter.clearSelection();
actionMode = null;
【问题讨论】:
非常感谢你拯救了我的一天。 不错的示例已经获取 api 数据并将其设置为适配器 UI,如何通过删除此示例实现操作模式缺少一些代码,我认为请提供完整或示例链接 动作模式已填充,当我按下第二个项目时,一次只选择一个项目作为上下文动作模式,它没有被选中,请帮助我 如果我的活动在我长按显示不幸错误时没有 recyclerview 数据,请帮助我 【参考方案1】:问题似乎来自FragmentToday.java
类的onItemLongClicked
方法。应该是:
@Override
public boolean onItemLongClicked(int position)
if (actionMode == null)
actionMode = ((AppCompatActivity) getActivity()).startSupportActionMode(actionModeCallback);
toggleSelection(position);
return true;
代替:
@Override
public boolean onItemLongClicked(int position)
if (actionMode != null)
((AppCompatActivity) getActivity()).startSupportActionMode(actionModeCallback);
toggleSelection(position);
return true;
【讨论】:
以上是关于在 recyclerview 片段中实现上下文操作模式的问题的主要内容,如果未能解决你的问题,请参考以下文章
片段内的 RecyclerView 的 Kotlin OnItemClickListener
Android:RecyclerView 不显示片段中的列表项
RecyclerView onClickListener 适用于所有片段
如何在 RecyclerView 的 CardView 中实现对 Item Click 的操作以显示结果