0

I am trying to use Otto for achieving the following use case.

I have a Viewpager with Fragments that contains a RecyclerView each. The recyclerviews show posts that the users post to the app. A new post button is attached to each of these Fragments. Once the post Button is clicked, the user is taken to a new activity and he posts the content there. When he comes back to the ViewPagerfragment screen again, I want the fragment screen to refresh and show the updated contents. I use otto for this.

I am able to make this work when only one fragment is present.

public class PlaceholderFragment extends Fragment {

private static final String ARG_SECTION_NUMBER = "section_number";


public static PlaceholderFragment newInstance(int sectionNumber) {
    PlaceholderFragment fragment = new PlaceholderFragment();
    Bundle args = new Bundle();
    args.putInt(ARG_SECTION_NUMBER, sectionNumber);
    fragment.setArguments(args);
    return fragment;
}


public PlaceholderFragment() {
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    BusProvider.getInstance().register(this);
}

I have the register method called in the onCreatemethod of the PlaceholderFrament. so obviously when multiple fragments are loaded multiple times, I get the following error. How do I handle this?

Process: com.four.xxxx.xx, PID: 9934
java.lang.IllegalArgumentException: Object already registered.
        at com.squareup.otto.Bus.register(Bus.java:222)
        at com.four.xxxx.xx.PlaceholderFragment.onCreateView(PlaceholderFragment.java:94)
        at android.app.Fragment.performCreateView(Fragment.java:2053)

Edit 1 : PagerAdapter Class as requested :

    public class FourScreenActivity extends Activity {

    SectionsPagerAdapter mSectionsPagerAdapter;
    ViewPager mViewPager;
    static final int POST_DEPT_REQUEST = 1;
    static final int POST_COLLEGE_REQUEST = 2;


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

        mSectionsPagerAdapter = new SectionsPagerAdapter(getFragmentManager());
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mSectionsPagerAdapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    public void postInSection1(View view) {
        Intent intent = new Intent(this, PostInSection1.class);
        startActivity(intent);

    }

    public void postInSection2(View view) {
        Intent intent = new Intent(this, PostInSection2.class);
        startActivity(intent);
    }


    public class SectionsPagerAdapter extends FragmentPagerAdapter {

        public SectionsPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {

            return PlaceholderFragment.newInstance(position + 1);
        }

        @Override
        public int getCount() {
            // Show 3 total pages.
            return 3;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            Locale l = Locale.getDefault();
            switch (position) {

                case 0:
                    return getString(R.string.title_section1).toUpperCase(l);
                case 1:
                    return getString(R.string.title_section2).toUpperCase(l);
                case 2:
                    return getString(R.string.title_section3).toUpperCase(l);
            }
            return null;
        }
    }

}
55597
  • 2,033
  • 1
  • 21
  • 40
  • Please add PagerAdapter class also. I think you might misuse it. It might be connected one Fragment object to multiple pages, not multiple Fragment instance in each page. – Youngjae Jun 05 '15 at 03:45
  • I use GreenRobot, but maybe Otto is the same. Do you unregister the bus?. I have found that with fragments it is best to register in onResume and unregister in onPause. – Smashing Jun 05 '15 at 05:44
  • @Smashing I dont understand how it will work, kindly explain. Read my comments for the answer given below. – 55597 Jun 05 '15 at 16:09
  • @Youngjae have a look at my answer, is this what you wanted me to check in your first question? – 55597 Jun 06 '15 at 03:22
  • @55597 // Yes. I did not know components of your implementation `SectionOneFragment` and others. I revise my implementation in order to show `ViewPagerAdapter`. Your implementation at answer will always recreate section fragments but mine recreates or gives existed one. So please consider mine. – Youngjae Jun 06 '15 at 03:52

2 Answers2

0

Your Viewpager seems fine. Put otto registrater/unregister at each onResume and onPause as below, not onCreateView.

@Override
public void onResume() {
    super.onResume();
    BusProvider.getInstance().register(this);
}

@Override
public void onPause() {
    super.onPause();
    BusProvider.getInstance().unregister(this);
}

And ViewPager implementation is as below.

public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
    private SparseArrayCompat<SectionFragmentInterface> fragmentSparseArrayCompat;

    public SectionsPagerAdapter (FragmentManager fm) {
        super(fm);
        fragmentSparseArrayCompat = new SparseArrayCompat<>();
    }

    @Override
    public Fragment getItem(int position) {
        SectionFragmentInterface fragment = fragmentSparseArrayCompat.get(position);

        switch (position) {
            case 0: {
                if (fragment == null) {
                    fragment = SectionOneListFragment.newInstance(position);
                }
            }
            break;
            case 1: {
                if (fragment == null) {
                    fragment = SectionTwoListFragment.newInstance(position);
                }
            }
            break;
        }

        fragmentSparseArrayCompat.put(position, fragment);

        return fragment;
    }

    @Override
    public int getCount() {
        return 2;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return "";
    }

}
Youngjae
  • 24,352
  • 18
  • 113
  • 198
  • BusProvider.getInstance().onPause(); ? – 55597 Jun 05 '15 at 14:25
  • @55597 // sorry. Editted. – Youngjae Jun 05 '15 at 14:34
  • The onPause gets called when i move to the next activity to post. Hence the whole point of using Otto is wasted. – 55597 Jun 05 '15 at 14:36
  • @55597 // right. as I said in comment at question, the reason why otto iss wasted is that, you know, your implementation recreates fragment always, so refresh content always. but consider mine as it will give more performance. – Youngjae Jun 06 '15 at 03:58
0

Solved it!

I have been passing the instance of the same class for all the three fragments and registering to the bus in each fragment onCreate method, therefore trying to register the same class again and again.

I now made a base class and create three different sub classes for the fragments and hence I am able to register and unregister at the respective classes without multiple registrations.

This is the code that I changed in FragmentPagerAdapter class's getItem method from the snippet given in the question.

 @Override
    public Fragment getItem(int position) {

        switch (position){
            case 0:
                return new SectionOneFragment();
            case 1:
                return new SectionTwoFragment();
            case 2:
                return new SectionThreeFragment();
        }

        //return PlaceholderFragment.newInstance(position + 1);
        return null;
    }

And now I call the bus.register() at these new class's onCreate methods, the subscribed method also is implemented at the respective classes.

55597
  • 2,033
  • 1
  • 21
  • 40
  • Although you solved your problem but for specific case. Its better to provide solution when you use only single `Fragment` across your `FragmentPagerAdapter` – blueware Mar 18 '19 at 12:59