Связь между вложенными фрагментами в Android
Я недавно узнал Как сделать вложенные фрагменты в Android. Хотя я не знаю, как должно происходить общение.
читать фрагмент коммуникации документация Я знаю, что
все сообщение фрагмент-к-фрагмента сделано через связанное Деятельность. Два фрагмента никогда не должны общаться напрямую.
это имеет смысл для фрагментов братьев и сестер в рамках деятельности, но это не имеет большого смысла для общения между фрагментами родителей и детей. Должен ли я пройти весь путь до действия только для дочернего фрагмента, чтобы поговорить с родительским фрагментом? Если ответ простой "да", то я могу это сделать. Если это "нет", то как будет выглядеть дизайн кода?
Я вижу вложенный фрагмент документации что можно использовать getParentFragment()
получить ссылку на родителя фрагмент. Значит ли это, что ребенок должен напрямую общаться с родителем? Это кажется противоположным тому, что поощряется нормальным фрагментом, сообщающимся с родительской активностью.
2 ответов
следуя совету Рахула шармы в комментариях, я использовал обратные вызовы интерфейса для связи от дочернего фрагмента к родительскому фрагменту и к деятельности. Я тоже отправил этот ответ в Code Review. Я беру номера-ответа нет (на момент написания этой статьи), чтобы быть признаком того, что нет никаких серьезных проблем с этим узором. Мне кажется, это согласуется с общим руководством, данным в официальном коммуникационный фрагмент docs.
пример проекта
следующий пример проекта расширяет пример, приведенный в вопросе. Он имеет кнопки, которые инициируют восходящую связь от фрагментов к активности и от дочернего фрагмента к родительскому фрагменту.
Я настроил макет проекта следующим образом:
Основным Видом Деятельности
действие реализует слушателей из обоих фрагментов, чтобы он мог получать от них сообщения.
необязательный TODO: если активность хотела инициировать связь с фрагментами, она могла бы просто получить прямую ссылку на них, а затем вызвать один из их общедоступных методов.
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity implements ParentFragment.OnFragmentInteractionListener, ChildFragment.OnChildFragmentToActivityInteractionListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.parent_fragment_container, new ParentFragment());
ft.commit();
}
@Override
public void messageFromParentFragmentToActivity(String myString) {
Log.i("TAG", myString);
}
@Override
public void messageFromChildFragmentToActivity(String myString) {
Log.i("TAG", myString);
}
}
Родительский Фрагмент
Родительский фрагмент реализует прослушиватель из дочернего фрагмента, чтобы он мог получать от него сообщения.
необязательный TODO: если Родительский фрагмент хотел инициировать связь с дочерним фрагментом, он может просто получить прямую ссылку на него, а затем вызвать один из его общедоступных методов.
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class ParentFragment extends Fragment implements View.OnClickListener, ChildFragment.OnChildFragmentInteractionListener {
// **************** start interesting part ************************
private OnFragmentInteractionListener mListener;
@Override
public void onClick(View v) {
mListener.messageFromParentFragmentToActivity("I am the parent fragment.");
}
@Override
public void messageFromChildToParent(String myString) {
Log.i("TAG", myString);
}
public interface OnFragmentInteractionListener {
void messageFromParentFragmentToActivity(String myString);
}
// **************** end interesting part ************************
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_parent, container, false);
view.findViewById(R.id.parent_fragment_button).setOnClickListener(this);
return view;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
Fragment childFragment = new ChildFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.replace(R.id.child_fragment_container, childFragment).commit();
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
}
Фрагмент Ребенка
Дочерний фрагмент определяет интерфейсы прослушивателя как для действия, так и для родительского фрагмента. Если Дочерний фрагмент нужен только для связи с одним из них, то другой интерфейс может быть удален.
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class ChildFragment extends Fragment implements View.OnClickListener {
// **************** start interesting part ************************
private OnChildFragmentToActivityInteractionListener mActivityListener;
private OnChildFragmentInteractionListener mParentListener;
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.child_fragment_contact_activity_button:
mActivityListener.messageFromChildFragmentToActivity("Hello, Activity. I am the child fragment.");
break;
case R.id.child_fragment_contact_parent_button:
mParentListener.messageFromChildToParent("Hello, parent. I am your child.");
break;
}
}
public interface OnChildFragmentToActivityInteractionListener {
void messageFromChildFragmentToActivity(String myString);
}
public interface OnChildFragmentInteractionListener {
void messageFromChildToParent(String myString);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
// check if Activity implements listener
if (context instanceof OnChildFragmentToActivityInteractionListener) {
mActivityListener = (OnChildFragmentToActivityInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnChildFragmentToActivityInteractionListener");
}
// check if parent Fragment implements listener
if (getParentFragment() instanceof OnChildFragmentInteractionListener) {
mParentListener = (OnChildFragmentInteractionListener) getParentFragment();
} else {
throw new RuntimeException("The parent fragment must implement OnChildFragmentInteractionListener");
}
}
// **************** end interesting part ************************
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_child, container, false);
view.findViewById(R.id.child_fragment_contact_activity_button).setOnClickListener(this);
view.findViewById(R.id.child_fragment_contact_parent_button).setOnClickListener(this);
return view;
}
@Override
public void onDetach() {
super.onDetach();
mActivityListener = null;
mParentListener = null;
}
}
хотя ответ @Suragch правильный, но я хочу добавить другой способ передачи данных между Fragments
или Activity
. Неважно, что это Activity
или Fragment
вы можете передать данные с шины событий в 3 шага:
1-Определение события (сообщения):
public class OrderMessage {
private final long orderId;
/* Additional fields if needed */
public OrderMessage(long orderId) {
this.orderId = orderId;
}
public long getOrderId() {
return orderId;
}
}
2-Регистрация и отмена регистрации событий: чтобы иметь возможность получать события, класс должен зарегистрироваться / отменить регистрацию для шины событий. Лучшее место для Activities
и Fragments
is onStart()
и onStop()
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
для того, чтобы получить событие, вы должны подписаться на это событие. Для этого добавьте @Subscribe
аннотация к одному из ваших методов в вашем классе.
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(OrderMessage message){
/* Do something for example: */
getContractDetails(message.getOrderId());
}
3 - после события
EventBus.getDefault().post(new OrderMessage(recievedDataFromWeb.getOrderId()));
больше документации и примеров можно найти здесь. Есть также другие библиотеки, такие как:Отто