Коммуникация между фрагментом и активностью - лучшие практики

Этот вопрос в основном заключается в том, чтобы запрашивать мнения о наилучшем способе обработки моего приложения. У меня есть три фрагмента, которые обрабатываются одним действием. Фрагмент A имеет один элемент, который можно щелкнуть на фотографии, а фрагмент B имеет 4 элемента, которые можно щелкнуть кнопками. Другой фрагмент просто отображает детали при щелчке по фотографии. Я использую ActionBarSherlock.

Screen shot

Кнопки "вперед" и "назад" должны изменить фотографию на следующую или предыдущую позицию соответственно. Я мог держать фотографию и кнопки в том же фрагменте, но хотел оставить их в отдельности, если бы захотел перестроить их в планшете.

Мне нужен совет - следует ли объединять фрагменты A и B? Если нет, мне нужно будет выяснить, как реализовать интерфейс для трех кликов.

Я рассмотрел использование Roboguice, но я уже расширяюсь, используя SherlockFragmentActivity, так что нет. Я видел упоминание Отто, но я не видел хороших уроков о том, как включить в проект. Как вы думаете, какая должна быть лучшая дизайнерская практика?

Мне также нужна помощь в выяснении того, как общаться между фрагментом и активностью. Я хотел бы сохранить некоторые данные "global" в приложении, например, id позы. Есть ли какой-то пример кода, который я могу видеть помимо информации разработчика Android-разработчика? Это не все так полезно.

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

Ответ 1

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

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

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

Есть хороший учебник по Простой блог разработчика о том, как делать именно такие вещи.

Я надеюсь, что это было полезно для вас!

Ответ 2

Предлагаемый метод связи между фрагментами - использовать обратные вызовы\слушатели, которыми управляет ваша основная активность.

Я думаю, что код на этой странице довольно ясен: http://developer.android.com/training/basics/fragments/communicating.html

Вы также можете сослаться на приложение IO 2012 Schedule, которое фактически является справочным приложением. Его можно найти здесь: http://code.google.com/p/iosched/

Кроме того, вот SO вопрос с хорошей информацией: как передавать данные между фрагментами

Ответ 3

Это реализуется интерфейсом обратного вызова:

Прежде всего, мы должны сделать интерфейс:

public interface UpdateFrag {
     void updatefrag();
}

В упражнении выполните следующий код:

UpdateFrag updatfrag ;

public void updateApi(UpdateFrag listener) {
        updatfrag = listener;
}

из события, с которого должен выполняться обратный вызов в Activity:

updatfrag.updatefrag();

Во фрагменте реализуем интерфейс в CreateView и делаем следующий код:

 ((Home)getActivity()).updateApi(new UpdateFrag() {
        @Override
        public void updatefrag() {
              .....your stuff......
        }
 });

Ответ 4

Я создал библиотеку аннотаций, которая может сделать бросок для вас. Проверь это. https://github.com/zeroarst/callbackfragment/

@CallbackFragment
public class MyFragment extends Fragment {

    @Callback
    interface FragmentCallback {
       void onClickButton(MyFragment fragment);
    }    
    private FragmentCallback mCallback;

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bt1
                mCallback.onClickButton(this);
                break;
            case R.id.bt2
                // Because we give mandatory = false so this might be null if not implemented by the host.
                if (mCallbackNotForce != null)
                mCallbackNotForce.onClickButton(this);
                break;
        }
    }
}

Затем он создает подкласс вашего фрагмента. И просто добавьте его в FragmentManager.

public class MainActivity extends AppCompatActivity implements MyFragment.FragmentCallback {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getSupportFragmentManager().beginTransaction()
            .add(R.id.lo_fragm_container, MyFragmentCallbackable.create(), "MY_FRAGM")
            .commit();
    }

    Toast mToast;

    @Override
    public void onClickButton(MyFragment fragment) {
        if (mToast != null)
            mToast.cancel();
        mToast = Toast.makeText(this, "Callback from " + fragment.getTag(), Toast.LENGTH_SHORT);
        mToast.show();
    }
}

Ответ 5

Для связи между Activity и Fragment есть несколько вариантов, но после большого чтения и опыта я обнаружил, что это можно возобновить следующим образом:

  • Activity хочет общаться с дочерним Fragment => Просто напишите общедоступные методы в своем классе Fragment, и пусть Activity вызовет их
  • Fragment хочет общаться с родителем Activity => Это требует немного больше работы, как предполагает официальная ссылка Android https://developer.android.com/training/basics/fragments/communicating, было бы неплохо определить interface который будет реализован Activity и который установит контракт для любой Activity которая хочет связаться с этим Fragment. Например, если у вас есть FragmentA, который хочет обмениваться данными с любой activity которая его включает, тогда определите FragmentAInterface который определит, какой метод FragmentA может вызвать для activities которые решат его использовать.
  • Fragment хочет связаться с другим Fragment => Это тот случай, когда вы получаете самую "сложную" ситуацию. Поскольку вам потенциально может понадобиться передать данные из FragmentA во FragmentB и наоборот, это может привести к определению 2 интерфейсов, FragmentAInterface который будет реализован FragmentB и FragmentAInterface который будет реализован FragmentA. Это начнет портить вещи. И представьте, если у вас есть еще несколько Fragment на месте, и даже родительская activity хочет с ними общаться. Что ж, этот случай - идеальный момент для создания общей ViewModel для activity и его fragment. Более подробная информация здесь https://developer.android.com/topic/libraries/architecture/viewmodel. По сути, вам нужно определить класс SharedViewModel, который содержит все данные, которые вы хотите разделить между activity и fragments которые будут нуждаться в передаче данных между ними.

В случае с ViewModel, в конце концов, все становится намного проще, поскольку вам не нужно добавлять дополнительную логику, которая делает вещи грязными в коде и беспорядочными. Кроме того, это позволит вам отделить сбор (посредством обращений к базе данных SQLite или API) данных от Controller (activities и fragments).

Ответ 6

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

Мое предложение - использовать шину событий. Шина событий - это реализация шаблона публикации/подписки.

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

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

Ответ 7

Я не уверен, что действительно понял, что вы хотите сделать, но предлагаемый способ общения между фрагментами - использовать обратные вызовы с Activity, а не напрямую между фрагментами. См. Здесь http://developer.android.com/training/basics/fragments/communicating.html

Ответ 8

Вы можете создать объявление публичного интерфейса с объявлением функции в фрагменте и реализовать интерфейс в активности. Затем вы можете вызвать функцию из фрагмента.

Ответ 9

Я использую Intents для передачи действий обратно в основное действие. Основная деятельность - слушать их, переопределяя OnNewIntent (намерение намерения). Основное действие переводит эти действия на соответствующие фрагменты, например.

Итак, вы можете сделать что-то вроде этого:

public class MainActivity extends Activity  {

    public static final String INTENT_ACTION_SHOW_FOO = "show_foo";
    public static final String INTENT_ACTION_SHOW_BAR = "show_bar";


   @Override
   protected void onNewIntent(Intent intent) {
        routeIntent(intent);
   }

  private void routeIntent(Intent intent) {
       String action = intent.getAction();
       if (action != null) {               
            switch (action) {
            case INTENT_ACTION_SHOW_FOO:
                // for example show the corresponding fragment
                loadFragment(FooFragment);
                break;
            case INTENT_ACTION_SHOW_BAR:
                loadFragment(BarFragment);
                break;               
        }
    }
}

Затем внутри любого фрагмента, чтобы показать фрагмент foo:

Intent intent = new Intent(context, MainActivity.class);
intent.setAction(INTENT_ACTION_SHOW_FOO);
// Prevent activity to be re-instantiated if it is already running.
// Instead, the onNewEvent() is triggered
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
getContext().startActivity(intent);