Destroy FragmentStatePagerAdapter instance with parent Fragment

1k Views Asked by At

I am not sure how to ask this. I tried in here, but I guess I was not clear enough. So, I thought I just write a small App to describe the situation. Please note, the App uses Googles SlidingTabLayout.

Long story short, at any point if I click Button1, the FrameLayout should contain Fragment1, removing Fragment2 (if exists). Therefore, FragmentViewPager should also be destroyed as Fragment2. However, even then if I change the orientation of my device, I get the Toast which is defined in the onCreate() method of FragmentViewPager.

Why FragmentViewPager's onCreate is called even if Fragment2 is paused/destroyed? Is it possible that, the Toast of FragmentViewPager will not be shown when Fragment2 is destroyed?

MainActivity:

package com.abdfahim.testproject;

import android.app.Fragment;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

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

        Button button1 = (Button) findViewById(R.id.button1);
        button1.setOnClickListener(onClickListener);

        Button button2 = (Button) findViewById(R.id.button2);
        button2.setOnClickListener(onClickListener);
    }


    private View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Fragment fragment;
            switch (v.getId()){
                case R.id.button1:
                    fragment = new Fragment1();
                    break;
                case R.id.button2:
                    fragment = new Fragment2();
                    break;
                default:
                    return;
            }
            getFragmentManager().beginTransaction().replace(R.id.frame_container, fragment, v.getTag().toString()).addToBackStack(null).commit();
        }
    };
}

Fragment1

package com.abdfahim.testproject;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class Fragment1 extends Fragment {

    public Fragment1(){}

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment1,container,false);
        setHasOptionsMenu(true);

        return rootView;
    }
}

Fragment2

package com.abdfahim.testproject;

import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;
import android.support.v13.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class Fragment2 extends Fragment {

    public Fragment2(){}

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment2,container,false);
        setHasOptionsMenu(true);

        CharSequence titles[]= {"Tab A", "Tab B"};

        // Creating The ViewPagerAdapter
        ViewPagerAdapter adapter =  new ViewPagerAdapter(getActivity().getFragmentManager(), titles, titles.length);
        ViewPager pager = (ViewPager) rootView.findViewById(R.id.pager);
        pager.setAdapter(adapter);

        // Assigning the Sliding Tab Layout View
        SlidingTabLayout tabs = (SlidingTabLayout) rootView.findViewById(R.id.tabs);

        // Setting the ViewPager For the SlidingTabsLayout
        tabs.setViewPager(pager);

        return rootView;
    }

    static class ViewPagerAdapter extends FragmentStatePagerAdapter {

        private CharSequence titles[];
        private int numbOfTabs;

        public ViewPagerAdapter(FragmentManager fm, CharSequence mTitles[], int mNumbOfTabs) {
            super(fm);

            this.titles = mTitles;
            this.numbOfTabs = mNumbOfTabs;

        }

        @Override
        public int getItemPosition(Object object) {
            return POSITION_NONE;
        }

        @Override
        public Fragment getItem(int position) {
            Bundle bundle = new Bundle();
            bundle.putString("displayText", "Inside Fragment 2, " + titles[position]);
            FragmentViewPager fragment = new FragmentViewPager();
            fragment.setArguments(bundle);
            return fragment;
        }

        // This method return the titles for the Tabs in the Tab Strip

        @Override
        public CharSequence getPageTitle(int position) {
            return titles[position];
        }

        // This method return the Number of tabs for the tabs Strip

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

    }
}

FragmentViewPager

package com.abdfahim.testproject;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

public class FragmentViewPager extends Fragment {

    public FragmentViewPager(){}

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_view_pager,container,false);
        setHasOptionsMenu(true);

        Bundle bundle = this.getArguments();
        TextView textView = (TextView) rootView.findViewById(R.id.tabText);
        textView.setText(bundle.getString("displayText"));

        return rootView;
    }

    @Override
    public void onStart() {
        super.onStart();
        Toast.makeText(getActivity(), "This is View Pager Fragment", Toast.LENGTH_SHORT).show();
    }
}
2

There are 2 best solutions below

3
On BEST ANSWER

when you use fragment inside another fragment. you use getChildFragmentManager() instead of getFragmentManager. You can call setAdapter() for the ViewPager from onCreateView() or onActivityCreated()

for more detail. have a look at it

Why it is not possible to use ViewPager within a Fragment? It actually is

1
On

For every click your OnClickListener creates the instance of Fragment2 and does not create Fragment1. That is due to the misuse of View#getTag.

In MainActivity#onCreate, change the if in the definition of onClickListener to this(using this answer):

switch (v.getId()){
        case R.id.button1:
            fragment = new Fragment1();
            break;
        case R.id.button2:
            fragment = new Fragment2();
            break;
        default:
            return;
    }

In your code, in the if that is checked upon a click (for example after clicking button1) android asks v (the clicked View) for its tag - but as none was set using View#setTag - it returns null which is of course not equal to the String object created for "button1", thus the if reverts to the else every time.