Как правильно перемещаться между фрагментами в BottomNavigationView?

Короче говоря, проблема:

У меня есть MainActivity, на котором расположены BottomNavigationView и FrameLayout. BottomNavigationView имеет 5 вкладок, и при нажатии на вкладку я добавляю фрагмент на этот FrameLayout. Но из какого-то фрагмента мне нужно открыть другой фрагмент. Из этого другого фрагмента мне нужно открыть другой. Каждый раз, когда мне нужно показать фрагмент, я уведомляю MainActivity из фрагмента, что ему нужно добавить еще один. Каждый фрагмент проверяет, реализует ли его активность интерфейс. И это раздражает. Итак, если у меня есть 100 фрагментов, MainActivity реализует слишком много интерфейсов. Это приводит к шаблонному коду. Итак, как правильно перемещаться между фрагментами, если их много?

Подробнее о проблеме:

Пожалуйста, сначала прочтите задачу в коротком разделе.

Как я уже сказал, у меня есть BottomNavigationView с 5 вкладками. Назовем фрагменты, отвечающие за каждую вкладку, как FragmentA, FragmentB, FragmentC, FragmentD, FragmentE. Я действительно знаю, как показывать эти фрагменты при нажатии вкладки. Я просто заменяю / добавляю эти фрагменты в действии. Но подождите, а что, если вы хотите перейти с FragmentA на FragmentF? После этого с FragmentF на FragmentG? Вот как я справляюсь с этой проблемой: из FragmentF или FragmentG я уведомляю MainActivity, что хочу изменить фрагмент. Но как они общаются с MainActivity? Для этого у меня есть интерфейсы внутри каждого фрагмента. MainActivity реализует эти интерфейсы. И вот проблема. MainActivity реализует слишком много интерфейсов, что приводит к шаблонному коду. Итак, как лучше всего перемещаться по фрагментам? Я даже не трогаю, что еще надо обрабатывать нажатия кнопок назад :)

Вот как выглядит мой код:

MainActivity, реализующий интерфейсы для изменения фрагментов при необходимости:

class MainActivity : AppCompatActivity(), DashboardFragment.OnFragmentInteractionListener,
    PaymentFragment.BigCategoryChosenListener, PaymentSubcategoryFragment.ItemClickedListener, PayServiceFragment.OnPayServiceListener, ContactListFragment.ContactTapListener, P2PFragment.P2PNotifier

Вот, например, мой метод onAttach для PaymentFragment:

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    if (context instanceof BigCategoryChosenListener) {
        listener = (BigCategoryChosenListener) context;
    } else {
        throw new RuntimeException(context.toString()
                + " must implement BigCategoryChosenListener");
    }
}

И с помощью этого listener я уведомляю об изменении фрагмента. И фрагмент в каждом я должен так сделать. Я не думаю, что это лучшая практика. Итак, все в порядке или есть способ лучше?

Ваш подход правильный, но действительно ли у вас есть 100 различных типов фрагментов? Вы уверены, что они не могут быть представлены несколькими фрагментами, которые просто обновляют свое содержание? Кажется маловероятным, что вам действительно нужно столько ...

Gennadii Saprykin 26.06.2018 11:13

@GennadiiSaprykin Спасибо за ответ. К сожалению, я вас не очень хорошо понял. Что вы имеете в виду под небольшим количеством фрагментов? У меня есть BottomNavigationView с 5 вкладками, и с каждой вкладки я могу переходить к другим фрагментам. Вы имеете в виду, что мне нужны фрагменты внутри фрагментов?

neo 26.06.2018 11:16

5 вкладок, каждая имеет один соответствующий фрагмент содержимого. Даже если они разные, это всего лишь один интерфейс, работающий с таким методом, как onTabClicked(int tab). Все ли эти 5 фрагментов доступны для навигации? Можете ли вы как-то обобщить логику при навигации? Пожалуйста, опишите подробнее, какой контент вы показываете и что происходит, когда вы перемещаетесь внутрь. Спасибо.

Gennadii Saprykin 26.06.2018 11:37

@abay - На мой взгляд, исходя из вашего описания, у вас может быть определенный набор фрагментов, скажем, для 5 вкладок 5 фрагментов, и вы можете заменять их, когда захотите. Для управления навигацией между ними есть навигатор, для этого будут вспомогательные методы экранной навигации. Как replaceFragment. Надеюсь это поможет.

Abhi 26.06.2018 11:39

@GennadiiSaprykin Обновленный вопрос с более подробной информацией

neo 26.06.2018 11:52

@Abhi Пожалуйста, посмотрите, чтобы обновить вопрос

neo 26.06.2018 11:53

abay - Хорошо, спасибо за подробное описание. Если мне нужно решить этот сценарий, я не буду беспокоить Mainactivity для взаимодействия. Учитывая, что все ваше представление фрагментов находится на уровне глубины 1. Вы можете использовать вспомогательный класс типа ScreenManager с Context (ActivityContext) в качестве параметра для вспомогательного метода replaceFragment. Надеюсь, я прояснил это. Также ваша обратная навигация по стеку будет работать нормально.

Abhi 26.06.2018 11:59

@abay спасибо! Итак, если проблема в том, что в MainActivity слишком много кода, вы можете сделать то, что сказал @Abhi - переместить его в какой-нибудь вспомогательный класс, такой как Navigator, просто для улучшения читабельности. Если у вас действительно много фрагментов, вам все равно придется где-то писать эту логику, будь то активность или навигатор, на самом деле не имеет значения.

Gennadii Saprykin 26.06.2018 12:00

Единственный способ уменьшить объем кода - это создать какое-то сопоставление между фрагментами и создать общий метод для замены фрагментов, который определит, какой фрагмент заполнять при навигации вниз, в зависимости от этого сопоставления. Но это сильно увеличит сложность и, скорее всего, того не стоит. Я думаю, что это нормально - иметь много кода, если он выполняет одну конкретную задачу, навигацию, и написан в одном месте, а не распределен по базе кода. Я думаю, что простой перенос кода во вспомогательный класс - лучший вариант.

Gennadii Saprykin 26.06.2018 12:02

@GennadiiSaprykin Еще раз спасибо. Давай попробуем в последний раз. Я обновляю вопросы, вставляя код. Может быть, это поможет вам глубже понять проблему и дать другие советы.

neo 26.06.2018 12:09

@Abhi Я обновляю вопросы, добавляя код. Что вы думаете об этом коде? Это нормально?

neo 26.06.2018 12:10
1
11
455
1

Ответы 1

Хорошо, что вам нужно, это что-то вроде этого в действии, где вы инициализируете свой BottomNavigationView.

bottomNavigationView.setOnNavigationItemSelectedListener(
    new BottomNavigationView.OnNavigationItemSelectedListener() {
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()) {

               case R.id.menu_1://Handle menu click - 
                     //Call Navigator helper to replace Fragment to Fragment A
                     break;  
                case R.id.menu_2:
                    //Call Navigator helper to replace Fragment to Fragment B
                     break;

                case R.id.menu_3:
                   //Call Navigator helper to replace Fragment to Fragment C
                     break;
                  }
            return true;
        }

});

Но замена фрагмента означает уничтожение предыдущего фрагмента. Это означает, что когда вы нажимаете назад, предыдущий фрагмент воссоздает и выполняет ненужные операции, такие как HTTP-запросы.

neo 26.06.2018 12:34

Ну, это зависит от того, что вы там делаете. Как правило, при правильном подходе к программированию HTTP-запрос будет запускаться от презентатора (MVP), а не от фрагмента, и фрагмент будет показывать данные, которые получены с сервера и кэшированы. Это также зависит от того, когда (когда preseneter задействован) выбираются данные. Также скажите, что когда целевой целевой фрагмент уже находится в backstack FragmentManager, вы можете напрямую перейти к целевому фрагменту.

Abhi 26.06.2018 12:51

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