Неверный fragment в ViewPager получает onContextItemВыбранный вызов

У меня есть приложение, которое показывает несколько fragmentов (одного типа) в ViewPager и у меня возникают проблемы с элементами контекстного меню. (Я использую библиотеку поддержки).

Когда в контекстном меню в одном из fragmentов выбирается элемент контекстного меню, неправильный fragment получает onContextItemSelected события onContextItemSelected .

Например, если я нахожусь на fragmentе № 3 в пейджере, вместо этого вместо него принимает fragment в позиции # 2. Если я вернусь к fragmentу № 2, вместо этого вместо этого вместо этого получит номер # 3.

У меня есть образец здесь .

(В настоящее время я работаю над этим в своем приложении, имея переменную mHandleContext в каждом fragmentе и mHandleContext / отключая ее при изменении страницы. Таким образом, вызов onContextItemSelected будет выходить на все fragmentы до тех пор, пока не будет вызван правый. )

Я что-то делаю неправильно или это ошибка в библиотеке поддержки? В качестве побочной заметки этого не произошло, когда я использовал ActionBarSherlock 3.5.1, у которого была собственная вилка библиотеки поддержки.

Так что это какое-то идиотское дизайнерское решение от Google или что-то, что просто совсем не считалось. Самый простой способ обойти это – обернуть вызов onContextItemSelected с помощью оператора if:

 if (getUserVisibleHint()) { // Handle menu events and return true } else return false; // Pass the event to the next fragment 

В библиотеке совместимости в ActionBarSherlock 3.5 был такой хак.

Это происходит из-за этого:

 public boolean dispatchContextItemSelected(MenuItem item) { if (mActive != null) { for (int i=0; i 

Как вы можете видеть, FragmentManager вызывает Fragment.onContextItemSelected для всех своих собственных fragmentов, пока не вернет true. В вашем примере я могу предложить такое исправление:

  public static class TestListFragment extends ListFragment { private int mNumber = 0; private ArrayList mItems; public static TestListFragment newInstance(int number) { Bundle args = new Bundle(); args.putInt("number", number + 1); TestListFragment fragment = new TestListFragment(); fragment.setArguments(args); return fragment; } public TestListFragment() {} @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mNumber = getArguments().getInt("number"); mItems = new ArrayList(); mItems.add("I am list #" + mNumber); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setListAdapter(new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, mItems)); registerForContextMenu(getListView()); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); menu.add(mNumber, 0, 0, "Hello, World!"); } @Override public boolean onContextItemSelected(MenuItem item) { if(item.getGroupId() == mNumber){ Log.d("ViewPagerContextMenuBug", "onContextItemSelected called for number " + mNumber); Toast.makeText(getActivity(), "onContextItemSelected called for number " + mNumber, Toast.LENGTH_SHORT).show(); return true; } return false; } } 

О, Google, я имею в виду WTF?

Проблема в том, что onContextItemSelected очень общий, и он вызывается для каждого пункта меню каждого fragmentа.

Вы можете использовать MenuItem.OnMenuItemClickListener, чтобы заставить меню fragmentа не использовать все onContextItemSelected , но только ту же функцию этого fragmentа.

Используйте следующую реализацию:

 @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = getActivity().getMenuInflater(); if (v == btnShare) { inflater.inflate(R.menu.share_menu, menu); for (int i = 0; i < menu.size(); ++i) { MenuItem item = menu.getItem(i); item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { onContextItemSelected(item); return true; } }); } } } @Override public boolean onContextItemSelected(MenuItem item) { AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); switch (item.getItemId()) { case R.id.print: // ... } } 

Использование намерений для каждого из пунктов меню работало хорошо для меня.

  @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextmenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = super.getActivity.getMenuInflater(); inflater.infalte(R.menu.list_item, menu); for(int i = 0; i < menu.size(); i++) { MenuItem item = menu.getItem(i); Intent intent = new Intent(); intent.putExtra(KEY_EXTRA_FRAGMENT_ID, this.fragmentId); if (item != null) { item.setIntent(intent); } } } @Override public boolean onContextItemSelected(MeniItem item) { Intent intent = item.getIntent(); if (intent != null) { if (intent.getIntExtra(KEY_EXTRA_FRAGMENT_ID, -1) == this.fragmentId) { // Implement code according the item function. return true; } } return super.onContextItemSelected(item); } 

Решение getUserVisibleHint() не работает для меня – оно всегда возвращает true даже если fragment отсутствует на экране. Решение getGroupId() не работает при раздувании меню из XML-ресурса, что является моей ситуацией.

Кажется, что если Android не изменится, любое решение всегда будет немного взломанным. Я создаю глобальную переменную для хранения ссылки идентификатора для текущего fragmentа в onCreateView . Затем я onCreateContextMenu его каждому ContextMenu MenuItem ContextMenu в onCreateContextMenu . Когда элемент выбран, я подтверждаю, что эти два идентификатора совпадают.

 private int myFragmentReference; @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Initialisation stuff myFragmentReference = 12345; } @Override public void onCreateContextMenu(ContextMenu contextMenu, View v, ContextMenu.ContextMenuInfo contextMenuInfo) { // Usual stuff int size = contextMenu.size(); for (int i = 0; i < size; i++) { MenuItem menuItem = contextMenu.getItem(i); Intent intent = new Intent(); intent.putExtra("id", myFragmentReference); menuItem.setIntent(intent); } } @Override public boolean onContextItemSelected(MenuItem menuItem) { int id = 0; Intent intent = menuItem.getIntent(); if (intent != null) { id = intent.getIntExtra("id", 0); } if (id == myFragmentReference) { // This is the currently displayed fragment } } 
  • Android-приложение для переноски для Android: srcCompat не показывает изображения
  • Ошибка раздувания classа android.support.design.widget.NavigationView
  • Как заменить устаревший файл android.support.v4.app.ActionBarDrawerToggle
  • Interesting Posts

    Есть ли способ избавиться от акцентов и преобразовать целую строку в обычные буквы?

    Почему я не могу получить доступ к своему веб-серверу за пределами сети?

    Как включить многозадачность с новой библиотекой поддержки Android Multidex

    Что со статической памятью в java?

    ICloud Drive занимает место на локальном диске?

    КлассNotFoundException / NoClassDefFoundError в моем веб-приложении Java

    Создание прокси-сервера веб-службы в Visual Studio из файла WSDL

    Разрешены ли скобки в CSS-селекторах?

    Почему у вас нет «List <List >» в Java?

    Строка подключения с использованием проверки подлинности Windows

    Географическое / геопространственное расстояние между 2 списками точек lat / lon (координаты)

    PhpStorm – преимущества редактирования развернутых файлов напрямую, а также загрузка и синхронизация

    Как использовать мою собственную базу данных sqlite?

    Наполнить вид / макет в другой макет?

    Как автоматически перезапустить MySQL и MongoDB, когда они не реагируют?

    Давайте будем гением компьютера.