Подтвердить что ты не робот

Основы Android Fragments: почему? Является ли это концептуально неправильным?

У меня есть вопрос о "правильном программировании" в Android.

В настоящее время я разрабатываю приложение, используя фрагменты. Он включает в себя динамически добавленные фрагменты для Activity, фрагменты, завышенные от XML, вложенные фрагменты из XML или динамически добавленные. Скажем, немного всего.

Концепция, на которой этот вопрос фокусируется, - это процесс коммуникации, связанный с фрагментами. Итак, я прочитал документы, и я не первый раз пытаюсь использовать фрагменты.

Здравый смысл (и документы) говорят, что если Фрагмент хочет говорить или общаться с ним, мы должны использовать интерфейс.

Пример:

TestFragment

public class TestFragment extends Fragment {

  private TestFragmentInterface listener; 

  public interface TestFragmentInterface {

      void actionMethod();

  }


  @Override
  public void onViewCreated(View view, Bundle savedInstanceState) {

      if (getActivity() instanceof TestFragmentInterface) {
          listener = (TestFragmentInterface) getActivity();
      }

      // sending the event
      if (listener != null) listener.actionMethod();
  }

}

TestActivity

public class Test implements TestFragmentInterface {

  @Override
  public void actionMethod() {
    ..
  }
}

Здесь все прекрасно.

Это улучшает повторное использование, так как мой TestFragment таким образом может взаимодействовать с любым видом Activity, поскольку Activity реализует интерфейс, который я объявляю.

Другой способ: активность может взаимодействовать с фрагментом, удерживая ссылку и вызывая ее общедоступные методы. Это также предложенный способ обмена фрагментарно-фрагментацией с использованием Activity как моста.

Это классно, но иногда кажется, что использование интерфейса для этого немного "слишком много".

Вопрос A

В сценарии фрагменты, которые я прикрепляю, имеют довольно целенаправленную роль, то есть они выполняются для этого конкретного действия и не будут использоваться иначе, концептуально неправильно игнорировать реализацию интерфейса и просто делать что-то вроде

((TestActivity) getActivity().myCustomMethod();

?

Это также относится к сценарию, где (не в моем случае, но просто принимая его как "в худшем случае" ), моя деятельность должна иметь дело с широким спектром этих РАЗЛИЧНЫХ фрагментов, то есть он должен реализовывать один метод для каждого фрагмента он должен справиться. Это приводит код к большому беспорядку "потенциально не необходимых строк".

Двигаемся дальше: все еще с использованием "сфокусированных" фрагментов, направленных на то, чтобы работать только определенным образом, что такое использование вложенных фрагментов?

Добавлено их как

public class TestFragment extends Fragment {


  private void myTestMethod() {

    NestedFragment nested = new NestedFragment();

    getChildFragmentManager()
      .beginTransaction()
      .add(R.id.container, nested)
      .commit();
  }

}

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

Вернемся к вопросу, как я должен себя вести в этой ситуации?

Вопрос B

1) должен ли я предоставить интерфейс в NestedFragment и сделать так, чтобы TestFragments реализовывал NestedFragmentInterface? В этом случае я буду действовать следующим образом

NestedFragment

public class NestedFragment extends Fragment {

  private NestedFragmentInterface listener; 

  public interface NestedFragmentInterface {

      void actionMethodNested();

  }


  @Override
  public void onViewCreated(View view, Bundle savedInstanceState) {

      if (getParentFragment() instanceof NestedFragmentInterface) {
          listener = (NestedFragmentInterface) getParentFragment();
      }

      // sending the event
      if (listener != null) listener.actionMethodNested();
  }

}

2) должен (или мог) игнорировать интерфейс и просто вызывать

getParentFragment().publicParentMethod();

?

3) должен ли я создать интерфейс в NestedFragment, но пусть активность реализует его, чтобы активность вызывала TestFragment?

Вопрос C

Что касается идеи использования Activity как моста между фрагментами, я считаю, что это сделано для правильного управления жизненным циклом всех этих объектов. Сохраняется ли возможность делать прямой фрагмент-фрагмент (используя интерфейс или напрямую вызывать общедоступные методы), пытаясь вручную обработать исключение, которое система может выбросить меня?

4b9b3361

Ответ 1

Я попытаюсь все это немного очистить.

Прежде всего, рассмотрите подход к настройке прослушивателя для фрагмента. Нехорошо устанавливать слушателя в методе onViewCreated, потому что он лидирует с избыточным слушателем реселлера, создавая любой фрагмент. Достаточно установить его в метод onAttach.

Я рассказал о кодовых строках. Заставьте меня заметить, хорошо, что BaseFragment реализовал обычное поведение в вашем приложении, так как FragmentListener создавал представление из ресурса.

И более того, чтобы уменьшить коды кода и получить часть повторного использования кода, вы можете использовать generic в BaseFragment. Итак, посмотрите следующий фрагмент кода:

public abstract BaseFragment<T extends BaseFragmentListener> extends Fragment {

  T mListener;

  public void onAttach(Activity activity) {
    super.onAttach(activity);
    if (Activity instanceof T)
      mListener = (T) activity; 
  }

  abstract int getLayoutResourceId();

  @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View layout = inflater.inflate(getLayoutResourceId(), null);
        // you can use some view injected tools here, mb ButterKnife 
        return layout;
    }
}

Ответ A (для вопроса A):

Если у вас есть фрагмент всего лишь одного действия, вам нужно решить: "Вам действительно нужно использовать фрагмент здесь?". Но mb хорошо иметь фрагмент точно для одного действия, чтобы извлечь некоторую логику представления из активности и очистить базовую логику. Но для очистки базовой логики архитектуры для вашего приложения используется Listeners. Это облегчит жизнь другим разработчикам.

Ответ B: Для вложенных фрагментов вам нужно решить, что им нужно, чтобы использовать точные действия или просто фрагменты и использовать его в качестве моста для другой системы. Если вы знаете, что вложенный фрагмент будет вложен все время, вам нужно объявить родительский фрагмент в качестве слушателя, иначе вы должны использовать другой подход.

Примечание: В качестве базового подхода к общению между diff частью приложения вы можете использовать события, попробуйте также взглянуть на шину событий, например. Это дает вам общий подход к общению, и вы можете извлекать логику вызова пользовательских методов слушателей и, более того, вся логика будет находиться в обработке событий, и у вас будет одна система посредников для сотрудничества.

Ответ C: Я частично объясняю один из подходов к сотрудничеству между фрагментами. Использование одного диспетчера событий позволяет избежать много слушателей для всех разных коммуникаций. Иногда это очень выгодно.

Или я думаю, что более целесообразно использовать Activity или другие классы в Activity, для посредника для сотрудничества Fragments, потому что во время жизненного цикла и обработки и много чего происходит в Fragments. И он фокусирует всю эту логику в одном месте и делает ваш код более понятным.

Надеюсь, мои соображения помогут вам.

Ответ 2

Я делаю все возможное, чтобы ответить на стену текста здесь:)

Вопрос A:

Фрагменты предназначены для повторного использования модулей, которые могут быть подключены и воспроизводиться с любой деятельностью. Из-за этого единственным правильным способом взаимодействия с активностью является наследование наследования интерфейса, который понимает фрагмент.

public class MapFragment extends Fragment {

  private MapFragmentInterface listener; 

  public interface MapFragmentInterface {

      //All methods to interface with an activity

  }


  @Override
  public void onViewCreated(View view, Bundle savedInstanceState) {
      // sending the event
      if (listener != null) listener.anyMethodInTheAboveInterface();
  }

}

Затем реализуем реализацию интерфейса

public class MainActivity extends Activity implement MapFragmentInterface{

//All methods need to be implemented here
}

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

((TestActivity) getActivity().myCustomMethod();

полагается на то, что ваш фрагмент может работать только в тестовой активности и, следовательно, "ломает" правила фрагментов.

Вопрос B и C:

Предполагая, что вы выполняете правильные рекомендации для фрагментов и что они являются независимыми модулями. Тогда у вас никогда не должно быть ситуации, когда фрагменты должны знать друг о друге. В 99% случаев, когда люди думают, что им нужны фрагменты, чтобы напрямую общаться, они могут перераспределить свою проблему в ситуации, которую я дал выше, используя MVC patten или что-то подобное. Попросите действия действовать как контроллер и сообщить фрагменты, когда им нужно обновить, а затем создать отдельное хранилище данных.