Коммуникация между фрагментом и активностью - лучшие практики
Этот вопрос в основном заключается в том, чтобы запрашивать мнения о наилучшем способе обработки моего приложения. У меня есть три фрагмента, которые обрабатываются одним действием. Фрагмент 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);