9

Ho hackerato insieme la mia prima app da un gruppo di tutorial. Con l'aiuto di uno di loro ho implementato un RecyclerView all'interno di un frammento che viene utilizzato dall'attività principale. Ora ho trovato another tutorial che voglio usare per implementare la multi-selezione con la modalità di azione contestuale. Il grosso problema è che il tutorial non sta usando un frammento. Ho provato a riscrivere il codice per adattarlo a un frammento. Ora sono in un punto dove non ottengo errori in Android Studio e le piste app, ma quando io in realtà faccio il LongClick per selezionare una voce, si blocca con un NullPointerException:Problemi con l'implementazione della modalità di azione contestuale nel frammento di recyclerview

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.view.ActionMode.setTitle(java.lang.CharSequence)' on a null object reference

Sono totalmente perso sul motivo per cui questo accade e con l'intera multi-selezione in generale.

penso che le parti pertinenti di ogni classi coinvolte sono:

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

} 
+0

Big Grazie mi hai salvato la giornata. –

+0

bel campione sono già dati API che ottengono e impostano l'interfaccia utente dell'adattatore, come implementare la modalità di azione con l'eliminazione di questo campione manca un codice penso che fornire collegamenti completi o di esempio – Harsha

+0

actionmode è popolato e un solo elemento è selezionato alla volta per contestuale modalità di azione quando premo il secondo oggetto non è selezionato, per favore aiutami a – Harsha

risposta

7

Il problema sembra essere dalla tua onItemLongClicked metodo della classe FragmentToday.java. Avrebbe dovuto essere:

@Override 
public boolean onItemLongClicked(int position) { 
    if (actionMode == null) { 
     actionMode = ((AppCompatActivity) getActivity()).startSupportActionMode(actionModeCallback); 
    } 

    toggleSelection(position); 

    return true; 
} 

invece di:

@Override 
public boolean onItemLongClicked(int position) { 
    if (actionMode != null) { 
     ((AppCompatActivity) getActivity()).startSupportActionMode(actionModeCallback); 
    } 

    toggleSelection(position); 

    return true; 
} 
Problemi correlati