Android: щелчок по контекстному меню приводит к изменению состояния переменных

В настоящее время я пытаюсь реализовать контекстное меню для своего приложения, в нем есть список задач, и когда пользователь долго нажимает на него, должно появиться контекстное меню, предоставляющее пользователю некоторые параметры в зависимости от выбранного элемента.

Реализация самого меню не была слишком сложной, и моя реализация дает ожидаемый результат:

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    if(v.getId() == R.id.list){ //check if the click comes from the listview
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
        menuChoosenTask = taskAdapter.getItem(info.position); //retrive the choosen task
        Log.e("CreateMenu", "Choose item with name " + menuChoosenTask.getTaskName());
        menu.setHeaderTitle(menuChoosenTask.getTaskName());

        int options = 3;
        if(menuChoosenTask.getTypeOfTask() == WeeklyTask.TYPE_TASK_WORK) options = 4;

        for(int i = 0; i < options; i++){
            menu.add(Menu.NONE, i, i, menuOptions[i]);
        }
    }
}

Но для обработки пользовательских кликов возникают проблемы и происходят странные вещи:

@Override
public boolean onContextItemSelected(MenuItem item) {
    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();

    final int menuItemIndex = item.getItemId();

    menuChoosenTask = taskAdapter.getItem(info.position);

    int choosenTaskId = menuChoosenTask.getId();
    String selectedOption = menuOptions[menuItemIndex];

    if(selectedOption.equals(getString(R.string.cm_option_edit))){
    //DO STUFF
    }
    if(selectedOption.equals(getString(R.string.cm_option_delete_for_everyday))){

    //DO STUFF

    }
    if(selectedOption.equals(getString(R.string.cm_option_delete_for_this_day)){
    //DO STUFF
    }

    return true;
}

Проблемы возникают, когда я пытаюсь получить menuChoosenTaskпо какой-то причине taskAdapter может уменьшить его размер, то есть из того, что я видел в отладчике: при создании меню taskAdapter имеет размер 4 а также info.position является 3 так что нет проблем, но когда я нажимаю, info.position все еще 3 но сейчас taskAdapter имеет размер 2, Поэтому я сначала попытался обойти это, установив menuChoosenTask в качестве глобальной переменной и просто установите ее состояние при создании меню и повторно используйте его, когда пользователь выбирает параметр, но по некоторым причинам переменная теряет свое состояние при выборе параметра и становится null, Мой вопрос: как я могу получить объект и почему происходят эти странные вещи?

РЕДАКТИРОВАТЬ:

Мне удалось немного сузить проблему: две функции, которые вы видите, находятся в классе DayFragment, и одна из его переменных задается дочерним классом при вызове, поэтому в основном происходит то, что первый метод (создание меню) вызывается от ребенка (скажем, второго и из того, что я видел: тот, что на моем экране), но второй метод (выбор опции) вызывается из другого, вот полный код класса плюс один из его подклассов:

DayFragment.java:

public abstract class DayFragment extends Fragment {

    protected int DAY_ID = 0;
    protected List<WeeklyTask> tasks;
    protected TaskAdapter taskAdapter;
    protected MainViewModel mainViewModel;
    protected AppDatabase mDB;
    protected String[] menuOptions = {"Edit", "Delete for this day", "Delete for everyday", "To-Do's"};

    protected WeeklyTask menuChoosenTask;

    public DayFragment(){}

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.tasks_list, container, false);

        setDayId();

        tasks = new ArrayList<>();
        taskAdapter = new TaskAdapter(getActivity(), tasks);
        mDB = AppDatabase.getInstance(getContext());

        ListView listView = rootView.findViewById(R.id.list);
        listView.setAdapter(taskAdapter);

        registerForContextMenu(listView);

        mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);

        setupFAB( (FloatingActionButton) rootView.findViewById(R.id.fab));
        setupViewModel();

        return rootView;

    }

    public abstract void setupFAB(FloatingActionButton fab);    
    protected abstract void setDayId();

    public void setupViewModel() {

        mainViewModel.getTasks().removeObservers(this);

        mainViewModel.getTasks().observe(this, new Observer<List<WeeklyTask>>() {
            @Override
            public void onChanged(@Nullable List<WeeklyTask> weeklyTasks) {


                taskAdapter.clear();
                int id = 0;
                WeeklyTask task;

                for(int i = 0; i < weeklyTasks.size(); i++){
                    task  = weeklyTasks.get(i);
                    if(task.getDays()[DAY_ID]){ // IF should be shown this day

                        taskAdapter.insert(task, id);
                        id++;
                    }
                }

                taskAdapter.notifyDataSetChanged();
            }
        });

    }

    public boolean atLeastOneTrue(boolean[] arr){
        boolean out = false;
        for(int i = 0; i < arr.length; i++){
            out  = out | arr[i];
        }
        return out;
    }


    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        if(v.getId() == R.id.list){ //check if the click comes from the listview
            AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
            menuChoosenTask = taskAdapter.getItem(info.position);
            Log.e("CreateMenu", "Choose item with name " + menuChoosenTask.getTaskName() + " for day " + DAY_ID);
            menu.setHeaderTitle(menuChoosenTask.getTaskName());

            int options = 3;
            if(menuChoosenTask.getTypeOfTask() == WeeklyTask.TYPE_TASK_WORK) options = 4;

            for(int i = 0; i < options; i++){
                menu.add(Menu.NONE, i, i, menuOptions[i]);
            }
        }
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
        Log.e("menuClicked", "menu for day " + DAY_ID + " clicked on item no " + info.position);
        final int menuItemIndex = item.getItemId();

        menuChoosenTask = taskAdapter.getItem(info.position);

        int choosenTaskId = menuChoosenTask.getId();
        String selectedOption = menuOptions[menuItemIndex];

        if(selectedOption.equals(getString(R.string.cm_option_edit))){
            //DOSTUFF
        }
        if(selectedOption.equals(getString(R.string.cm_option_delete_for_everyday))){

         //DOSTUFF
        }
        if(selectedOption.equals(getString(R.string.cm_option_delete_for_this_day))){
//DOSTUFF    
        }

        return true;
    }

}

Один из его детских классов (их 7):

public class MondayFragment extends DayFragment {

    public static final int DAY_ID = 0;

    public void setDayId(){
        super.DAY_ID = DAY_ID;
    }
}

Все эти фрагменты показаны в PagerAdapter (в сочетании с пейджером представления), так что я вроде как понимаю, почему это происходит, но я не знаю, как это предотвратить.

1 ответ

Хорошо, я просто потратил полтора часа на поиски в интернете и наконец нашел решение:

Неправильный фрагмент в ViewPager получает вызов onContextItemSelected

Поскольку я не до конца понимал, что пошло не так, мне понадобилось очень много времени, чтобы найти это. Так что мой плохой и извините за все неприятности

Другие вопросы по тегам