RonEskinder
RonEskinder

Reputation: 527

FragmentTabHost getting empty fragments after popBackStack

I have tried every post in StackOverflow and have not been successful, i have a FragmentTabHost activity with tabs A B C D E

When i go to tab A and then go to tab B everything is ok, but if i return to tab A is blank, then return to tab B is also blank!!

A -> B -> A = Blank -> B = blank

I followed this post to get it working Dynamically changing the fragments inside a fragment tab host?, but the transition between tabs is not working.

I have tried changing my BaseContainerFragment to use getSupportFragmentManager instead of getChildFragmentManager but was unsuccessful, also removing addToBackStack(null) at this point im out of ideas, any help here will be appreciated, thanks.

This is the mainActivity that contain code for creating tabs using fragment.

public class ActivityMain extends FragmentActivity {

    public static final String TAB_1_TAG = "tab_1";
    public static final String TAB_2_TAG = "tab_2";
    public static final String TAB_3_TAG = "tab_3";
    public static final String TAB_4_TAG = "tab_4";
    public static final String TAB_5_TAG = "tab_5";
    private FragmentTabHost mTabHost;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
        mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
        mTabHost.getTabWidget().setDividerDrawable(null);
        mTabHost.getTabWidget().setStripEnabled(false);

        mTabHost.addTab(mTabHost.newTabSpec(TAB_1_TAG).setIndicator("", getResources().getDrawable(R.drawable.tab_account)), FragmentAccountContainer.class, null);
        mTabHost.addTab(mTabHost.newTabSpec(TAB_2_TAG).setIndicator("", getResources().getDrawable(R.drawable.tab_discounts)), FragmentPromotionsContainer.class, null);
        mTabHost.addTab(mTabHost.newTabSpec(TAB_3_TAG).setIndicator("", getResources().getDrawable(R.drawable.tab_payment)), FragmentAccountContainer.class, null);
        mTabHost.addTab(mTabHost.newTabSpec(TAB_4_TAG).setIndicator("", getResources().getDrawable(R.drawable.tab_gas)), FragmentAccountContainer.class, null);
        mTabHost.addTab(mTabHost.newTabSpec(TAB_5_TAG).setIndicator("", getResources().getDrawable(R.drawable.tab_rest)), FragmentAccountContainer.class, null);
    }

    @Override
    public void onBackPressed() {
        boolean isPopFragment = false;

        String currentTabTag = mTabHost.getCurrentTabTag();
        Log.e("ActivityMain", "currentTabTag: " + currentTabTag);
        if (currentTabTag.equals(TAB_1_TAG)) {
            isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(TAB_1_TAG)).popFragment();
        } else if (currentTabTag.equals(TAB_2_TAG)) {
            isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(TAB_2_TAG)).popFragment();
        } else if (currentTabTag.equals(TAB_3_TAG)) {
            isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(TAB_3_TAG)).popFragment();
        } else if (currentTabTag.equals(TAB_4_TAG)) {
            isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(TAB_4_TAG)).popFragment();
        } else if (currentTabTag.equals(TAB_5_TAG)) {
            isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(TAB_5_TAG)).popFragment();
        }
        Log.e("ActivityMain", "isPopFragment: " + isPopFragment);
        if (!isPopFragment) {
            finish();
        }
    }
}

This is my BaseContainerFragment that allows backtracking and replacment of fragments

public class BaseContainerFragment extends Fragment {

    public void replaceFragment(Fragment fragment, boolean addToBackStack) {
        FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
        if (addToBackStack) {
            transaction.addToBackStack(null);
        }
        transaction.replace(R.id.container_framelayout, fragment);
        transaction.commit();
        getChildFragmentManager().executePendingTransactions();
    }

    public boolean popFragment() {
        Log.e("test", "pop fragment: " + getChildFragmentManager().getBackStackEntryCount());
        boolean isPop = false;
        if (getChildFragmentManager().getBackStackEntryCount() > 0) {
            isPop = true;
            getChildFragmentManager().popBackStack();
        }
        return isPop;
    }
}

This is container for the first Tab (this tab holds 2 activities, one is main, and another is called on listview Click)

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    myPrefs = this.getActivity().getSharedPreferences("getLogin", Context.MODE_PRIVATE);
    idUser = myPrefs.getInt("idUser", 0);

    d(TAG, "idUser: " + idUser);
    /*
    Map<String,?> keys = myPrefs.getAll();

    for(Map.Entry<String,?> entry : keys.entrySet()){
        Log.d("map values",entry.getKey() + ": " +
                entry.getValue().toString());
    }
    */
    context = getActivity();
    pDialog = new SweetAlertDialog(context, PROGRESS_TYPE);


    // Check if Internet present
    if (!isOnline(context)) {
        // Internet Connection is not present
        makeText(context, "Error en la conexion de Internet",
                LENGTH_LONG).show();
        // stop executing code by return
        return;
    }

    new asyncGetFeedClass(context).execute();

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.activity_cardholder, container, false);

    toolbar = (Toolbar) v.findViewById(R.id.toolbar);
    TextView mTitle = (TextView) toolbar.findViewById(toolbar_title);
    mTitle.setText("TARJETAS");

    list = (ListView) v.findViewById(R.id.list);

    // Click event for single list row
    list.setOnItemClickListener(new AdapterView.OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                                int position, long id) {

            FragmentAccount fragment = new FragmentAccount();
            // if U need to pass some data
            Bundle bundle = new Bundle();

            if (listBalance.get(position).get(TAG_ACCOUNT_BANKACCOUNTS_ID) != null) {
                bundle.putString("idBankAccount", listBalance.get(position).get(TAG_ACCOUNT_BANKACCOUNTS_ID));
                bundle.putString("idGiftCard", "0");
            } else if (listBalance.get(position).get(TAG_ACCOUNT_GIFTCARDS_ID) != null) {
                bundle.putString("idGiftCard", listBalance.get(position).get(TAG_ACCOUNT_GIFTCARDS_ID));
                bundle.putString("idBankAccount", "0");
            } else {
                bundle.putString("idBankAccount", "0");
                bundle.putString("idGiftCard", "0");
            }

            fragment.setArguments(bundle);
            ((BaseContainerFragment) getParentFragment()).replaceFragment(fragment, false);
        }
    });

    return v;
}

The main class for Tab #1

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    myPrefs = this.getActivity().getSharedPreferences("getLogin", Context.MODE_PRIVATE);
    idUser = myPrefs.getInt("idUser", 0);

    d(TAG, "idUser: " + idUser);
    /*
    Map<String,?> keys = myPrefs.getAll();

    for(Map.Entry<String,?> entry : keys.entrySet()){
        Log.d("map values",entry.getKey() + ": " +
                entry.getValue().toString());
    }
    */
    context = getActivity();
    pDialog = new SweetAlertDialog(context, PROGRESS_TYPE);

    // Check if Internet present
    if (!isOnline(context)) {
        // Internet Connection is not present
        makeText(context, "Error en la conexion de Internet",
                LENGTH_LONG).show();
        // stop executing code by return
        return;
    }

    Bundle bundle = this.getArguments();
    idBankAccount = Integer.parseInt(bundle.getString(FragmentCardHolder.TAG_ACCOUNT_BANKACCOUNTS_ID, "0"));
    idGiftCard = Integer.parseInt(bundle.getString(FragmentCardHolder.TAG_ACCOUNT_GIFTCARDS_ID, "0"));

    if(idBankAccount > 0){
        new asyncGetBankTransactions(context).execute();
    } else if(idGiftCard > 0) {
        new asyncGetGiftCardTransactions(context).execute();
    } else {
        new asyncGetX111Transactions(context).execute();
    }
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.activity_account, container, false);

    toolbar = (Toolbar) v.findViewById(id.toolbar);
    TextView mTitle = (TextView) toolbar.findViewById(toolbar_title);
    mTitle.setText("MI CUENTA");
    toolbar.setNavigationIcon(R.drawable.icon_user);
    toolbar.setNavigationOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            goToCards();
        }
    });

    layoutAccount = (LinearLayout) v.findViewById(id.layoutAccount);
    layoutGetCredit = (LinearLayout) v.findViewById(id.layoutGetCredit);
    layoutTransactions = (LinearLayout) v.findViewById(id.layoutTransactions);

    btnAccount = (Button) v.findViewById(id.btnMyBalance);
    btnGetCredit = (Button) v.findViewById(id.btnGetCredit);
    btnSendCredit = (Button) v.findViewById(id.btnSendCredit);
    btnTransactions = (Button) v.findViewById(id.btnTransactions);

    list = (ListView) v.findViewById(id.list);

    btnTransactions.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            layoutAccount.setVisibility(View.GONE);
            layoutGetCredit.setVisibility(View.GONE);
            layoutTransactions.setVisibility(View.VISIBLE);
        }
    });

    btnGetCredit.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            layoutAccount.setVisibility(View.GONE);
            layoutGetCredit.setVisibility(View.VISIBLE);
            layoutTransactions.setVisibility(View.GONE);
        }
    });

    btnAccount.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            layoutAccount.setVisibility(View.VISIBLE);
            layoutGetCredit.setVisibility(View.GONE);
            layoutTransactions.setVisibility(View.GONE);
        }
    });

    return v;
}

private void goToCards() {
    FragmentCardHolder fragment = new FragmentCardHolder();
    ((BaseContainerFragment) getParentFragment()).replaceFragment(fragment, true);
}

Upvotes: 2

Views: 1643

Answers (2)

Beloo
Beloo

Reputation: 9925

I think the problem is in hidden part of code where you add first fragment to container (FragmentAccountContainer and FragmentPromotionsContainer classes). I suggest you to create abstract method in BaseContainerFragment.class with signature by example protected abstract Fragment getFirstFragment(); So concrete container class will override this method and return new instance of a first fragment to super class and then in parent class add it to fragment container with using add transaction.

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState == null) {
        addFragment(getFirstFragment(), false);
    }
}

Note you should check if savedInstanceState is null before adding fragment to avoid dublicates in case activity recreation by system. In nested fragments you could use replace like you did it ((BaseContainerFragment) getParentFragment()).replaceFragment(___, true);

Also i have a few suggestions for you code. You couldn't just avoid overriding onBackPressed in activity like @NecipAllef suggests, because of known bug with default back logic and child fragment manager , but you could simplify call to popFragment like

@Override
public void onBackPressed() {
    String currentTabTag = mTabHost.getCurrentTabTag();
    boolean isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(currentTabTag)).popFragment();
    if (!isPopFragment) {
        super.onBackPressed();
    }
}

And for setting bundles to fragment i suggest use fabric method pattern, like

public class TestFragment extends Fragment {
    public static Fragment newInstance(String text){
        Fragment fragment = new TestFragment();
        Bundle args = new Bundle();
        args.putString("text", text);
        fragment.setArguments(args);
        return fragment;
    }
}

Ps: i created for you a simple project with described logic

Upvotes: 2

NecipAllef
NecipAllef

Reputation: 506

Why are you keeping track of Fragments and popping them by yourself? You don't need to do that, and you shouldn't override onBackPressed(). Let FragmentManager handle the fragment transactions.

If you have fragments inside an activity, use

FragmentManager fManager = getFragmentManager();

or if you want to support devices prior to Android 3.0, use

FragmentManager fManager = getSupportFragmentManager();

if fragments are inside another fragment, then use

FragmentManager fManager = getChildFragmentManager();

After you have fManager, to show a fragment, use

fManager.beginTransaction().add(R.id.fragment_parent, new FirstTabFragment()).commit();

where fragment_parent is the parent view which you want to place your fragments.

When you want to switch to next fragment, use

fManager.beginTransaction().replace(R.id.fragment_parent, new SecondTabFragment())
                           .addToBackStack(null)
                           .commit();

Since you add it to back stack, you will see your first fragment when you press back. That's it.

Moreover, as you can easily realize this will cause your fragments to be created from scratch every time, you can prevent this by initializing them once and reuse them.

HTH

Upvotes: 1

Related Questions