Search code examples
androidandroid-fragmentsbroadcastreceiverfragmentstatepageradapter

Fragment is cleared when navigated in FragmentStatePagerAdapter


I have an activity that contains a FragmentStatePagerAdapter within this FragmentStatePagerAdapter there are three fragments. Or well, they get initiated when the proper getItem() is called.

The activity does a data intensive task, and when it is finished sends a broadcast. I have registered a broadcast receiver in every fragment within the FragmentStatePagerAdapter.

Now this all works fine except for one thing:

  • When we scroll to the fragment at position 2 (both position 1 and 2 work properly) the fragment at position 0 is cleared and doesn't return.

Here are some of my code samples:

The FragmentStatePagerAdapter

public class MessagePagerAdapter extends FragmentStatePagerAdapter {

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

@Override
public Fragment getItem(int arg0) {
    if(arg0 == 0) {
        Fragment fragment = new RecentConversationFragment();
        return fragment;
    } else if(arg0 == 1) {
        Fragment fragment = new PrivateConversationFragment();
        return fragment;
    } else {
        Fragment fragment = new ClanConversationFragment();
        return fragment;
    }
}

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


@Override
public CharSequence getPageTitle(int position) {
    if(position == 0) {
        return "Recent";
    } else if(position == 1) {
        return "Private";
    } else {
        return "Clan";
    }
}

The relevant parts of the activity

When the data is received I broadcast an intent

Intent recentIntent = new Intent("MESSAGE_LOADER_RECENT");
MessageActivity.this.sendBroadcast(recentIntent);

This broadcast is received in my fragment like this:

private void createReceiver() {
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("MESSAGE_LOADER_RECENT");
    receiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            fetchMessages();
        }
    };

    getActivity().getApplicationContext().registerReceiver(receiver,
            intentFilter);

}

private void fetchMessages() {
    this.conversations = mActivity.getRecentPrivateConversations();
    messageListView.setAdapter(new ConversationListAdapter(mActivity,
            R.layout.conversation_row, conversations));
    messageListView.setDivider(null);
    messageListView.setDividerHeight(0);
    mActivity.recentConversationBroadcastReceived = true;
    messageListView.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) {
            mActivity.navigateToConversation(conversations.get(position));
        }
    });

}

Note that I set mActivity.recentConversationBroadcastReceived = true, I do this because I keep sending broadcasts like this:

In the viewPager.setOnPageChangeListener,

        @Override
        public void onPageSelected(int arg0) {
            //here we check whether a broadcast is already sent to the
            //specific fragment, if not we need to send one
            if (arg0 == 0 || arg0 == 1) {
                // recent or private
                if (MessageActivity.this.loadedConversations != null) {
                    // check if the fragment already received a broadcast
                    if (arg0 == 0 && !recentConversationBroadcastReceived) {
                        Intent intent = new Intent("MESSAGE_LOADER_RECENT");
                        MessageActivity.this.sendBroadcast(intent);
                    } else if (arg0 == 1
                            && !privateConversationBroadcastReceived) {
                        Intent intent = new Intent("MESSAGE_LOADER_PRIVATE");
                        MessageActivity.this.sendBroadcast(intent);
                    }
                }
            } else {
                // clan
                if (!clanConversationBroadcastReceived
                        && MessageActivity.this.loadedClanConversations != null) {
                    Intent intent = new Intent("MESSAGE_LOADER_CLAN");
                    MessageActivity.this.sendBroadcast(intent);
                }
            }
        }

I do this because when I send a broadcast it isn't guaranteed that the current active fragment is the fragment that actually uses the data, and the fragment might not be initiated. So I send a broadcast on every page change until it is received.

I hope someone can help me with this issue.


Solution

  • Ugh. I hate answering my own questions.

    This problem can be avoided by setting the offScreenPageLimit of the ViewPager. The default limit is 2, but I had 3 fragments so that is why my fragment at position 0 got recreated everytime. So the solution was:

    viewpager.setOffscreenPageLimit(2);
    

    Source: Android : FragmentPagerAdapter don't saved the state of Fragment?

    Of course thank you to the people who helped me.