Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Communication between Fragments in ViewPager

I'm trying to do this: http://android-er.blogspot.com/2012/06/communication-between-fragments-in.html Except that I'm using a FragmentStatePagerAdapter

I have an Activity with two fragments(FragmentA & FragmentB)

FragmentA has an edittext and a button, FragmentB has a textview

Now all I want is that whenever I enter something in the edittext and click the button, that something will appear on my textview.

MainActivity:

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)

Whenever I click the button on my first fragment, my app crashes. What the hell is the problem?

like image 657
general_bearbrand Avatar asked Dec 09 '13 15:12

general_bearbrand


4 Answers

  1. You could use Intents (register broadcast receiver in fragment B and send broadcasts from fragment A.
  2. Use EventBus: https://github.com/greenrobot/EventBus. It's my favorite approach. Very convinient to use, easy communications between any components (Activity & Services, for example).

Steps to do:

First, create some class to represent event when your text changes:

public class TextChangedEvent {
  public String newText;
  public TextChangedEvent(String newText) {
      this.newText = newText;
  }
}

Then, in fragment A:

//when text changes
EventBus bus = EventBus.getDefault();
bus.post(new TextChangedEvent(newText));

in fragment 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);
}
like image 157
Rodion Altshuler Avatar answered Sep 30 '22 18:09

Rodion Altshuler


Fragments have access to there parent Activity.
Therefore the simplest approach is to register a callback in the parent Activity.

Update: Submit cache added to 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);
        }
    }
like image 31
Paradiesstaub Avatar answered Sep 30 '22 18:09

Paradiesstaub


I use Mr. Rodion's solution above. But in addition, Android Studio asked me to add @Subscribe annotation before onEvent method.

Like this:

@Subscribe
public void onEvent(TextChangedEvent event) {
    textView.setText(event.newText);
}

According to EventBus’ API:

Subscribers implement event handling methods (also called “subscriber methods”) that will be called when an event is posted. These are defined with the @Subscribe annotation. Please note that with EventBus 3 the method name can be chosen freely (no naming conventions like in EventBus 2).

like image 29
mcanvar Avatar answered Sep 30 '22 17:09

mcanvar


FragmentB is not even created until you switch to it so fragmentB.updateText(textPassToB); gives you NullPointerException.

You will need to store the text from the EditText in your activity and later when (if) the FragmentB is created you will need to read value from it.

like image 42
Ognyan Avatar answered Sep 30 '22 17:09

Ognyan