Связь между фрагментами в ViewPager
Я пытаюсь сделать это: http://android-er.blogspot.com/2012/06/communication-between-fragments-in.html За исключением того, что я использую FragmentStatePagerAdapter
У меня есть активность с двумя фрагментами (FragmentA & FragmentB)
FragmentA имеет текст редактирования и кнопку, FragmentB имеет текстовое представление
Теперь все, что я хочу, это чтобы каждый раз, когда я вводил что-то в тексте редактирования и нажимал кнопку, что-то появлялось в моем текстовом виде.
Основная деятельность:
public class MainActivity extends FragmentActivity {
ViewPager viewPager = null;
String TabFragmentB;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager)findViewById(R.id.pager);
FragmentManager fragmentManager = getSupportFragmentManager();
viewPager.setAdapter(new MyAdapter(fragmentManager));
}
public class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter (FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int i) {
Fragment fragment = null;
if (i == 0)
{
fragment = new FragmentA();
}
if (i == 1)
{
fragment = new FragmentB();
}
return fragment;
}
@Override
public int getCount() {
return 2;
}
}
public void setTabFragmentB(String t) {
TabFragmentB = t;
}
public String getTabFragmentB() {
return TabFragmentB;
}
}
Fragmenta:
public class FragmentA extends Fragment {
EditText et;
Button bt;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fraga, container, false);
et = (EditText)v.findViewById(R.id.edit1);
bt = (Button)v.findViewById(R.id.button1);
bt.setOnClickListener(Click);
return v;
}
OnClickListener Click = new OnClickListener(){
@Override
public void onClick(View v) {
String textPassToB = et.getText().toString();
String TabOfFragmentB = ((MainActivity)getActivity()).getTabFragmentB();
FragmentB fragmentB = (FragmentB)getActivity()
.getSupportFragmentManager()
.findFragmentByTag(TabOfFragmentB);
fragmentB.updateText(textPassToB);
}
};
}
FragmentB:
public class FragmentB extends Fragment {
TextView tv;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragb, container, false);
tv = (TextView)v.findViewById(R.id.text1);
String myTag = getTag();
((MainActivity)getActivity()).setTabFragmentB(myTag);
return v;
}
public void updateText(String t){
tv.setText(t);
}
}
LogCat:
FATAL EXCEPTION: main
java.lang.NullPointerException
at lmf.sample1.FragmentA$1.onClick(FragmentA.java:43)
at android.view.View.performClick(View.java:4212)
at android.view.View$PerformClick.run(View.java:17476)
at android.os.Handler.handleCallback(Handler.java:800)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5371)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
at dalvik.system.NativeStart.main(Native Method)
Всякий раз, когда я нажимаю кнопку на моем первом фрагменте, мое приложение вылетает. В чем, чёрт возьми, проблема?
4 ответа
- Вы можете использовать Intents (зарегистрировать приемник трансляции во фрагменте B и отправить трансляции из фрагмента A.
- Используйте EventBus: https://github.com/greenrobot/EventBus. Это мой любимый подход. Очень удобное в использовании, простое взаимодействие между любыми компонентами (например, Activity & Services).
Шаги, чтобы сделать:
Сначала создайте некоторый класс для представления события при изменении вашего текста:
public class TextChangedEvent {
public String newText;
public TextChangedEvent(String newText) {
this.newText = newText;
}
}
Затем во фрагменте А:
//when text changes
EventBus bus = EventBus.getDefault();
bus.post(new TextChangedEvent(newText));
во фрагменте B:
EventBus bus = EventBus.getDefault();
//Register to EventBus
@Override
public void onCreate(SavedInstanceState savedState) {
bus.register(this);
}
//catch Event from fragment A
public void onEvent(TextChangedEvent event) {
yourTextView.setText(event.newText);
}
Фрагменты имеют доступ к там родительской активности.
Поэтому самый простой подход заключается в регистрации обратного вызова в родительском Activity.
Обновление: добавьте кеш, добавленный в MainActivity.
public class MainActivity extends FragmentActivity {
private OnButtonClicked mOnButtonClicked;
private String mSubmitCache;
public interface OnButtonClicked {
void submit(final String s);
}
public void setOnButtonClicked(final OnButtonClicked c) {
mOnButtonClicked = c;
// deliver cached string, if any
if (TextUtils.isEmpty(mSubmitCache) == false) {
c.submit(mSubmitCache);
}
}
public void buttonClicked(final String s) {
if (mOnButtonClicked == null) {
// if FragmentB doesn't exist jet, cache value
mSubmitCache = s;
return;
}
mOnButtonClicked.submit(s);
}
}
public class FragmentA extends Fragment implements OnClickListener {
private MainActivity mMain;
private Button mButton;
@Override public onAttach(Activity a) {
mMain = (MainActivity) a;
}
@Override public void onClick(View v) {
mMain.buttonClicked("send this to FragmentB.");
}
}
public class FragmentB extends Fragment implements MainActivity.OnButtonClicked {
private MainActivity mMain;
private TextView mTextView;
// Called when the fragment's activity has been created
// and this fragment's view hierarchy instantiated
@Override public void onActivityCreated(Bundle savedState) {
mMain = (MainActivity) getActivity();
mMain.setOnButtonClicked(this);
}
@Override void submit(final String s) {
mTextView.setText(s);
}
}
Я использую решение мистера Родиона выше. Но кроме того, Android Studio попросила меня добавить @Subscribe
аннотация перед onEvent
метод.
Как это:
@Subscribe
public void onEvent(TextChangedEvent event) {
textView.setText(event.newText);
}
Согласно API EventBus:
Подписчики реализуют методы обработки событий (также называемые "методы подписчика"), которые будут вызываться при публикации события. Они определяются с помощью аннотации @Subscribe. Обратите внимание, что в EventBus 3 имя метода можно выбирать свободно (без соглашений об именах, как в EventBus 2).
FragmentB даже не создается, пока вы не переключитесь на него так, fragmentB.updateText(textPassToB);
дает вам NullPointerException.
Вам нужно будет сохранить текст из EditText в вашей деятельности, и позже, когда (если) будет создан FragmentB, вам нужно будет прочитать значение из него.