My app has Navigation Drawer with two items: a ViewPager (inside a Fragment) and SupportMapFragment.
ViewPager use a FragmentStatePagerAdapter and getItem(int position) return two Fragments.
When I open navigation drawer and I select "item 1" (SupportMapFragment), the other Fragment (ViewPager is inside of this) execute onDestroy() method but this method doesn't destroy the Fragments created by the adapter so when I select "item 0" again , my app create the ViewPager with its two items and the other two Fragments which ViewPager didn't remove.
This problem create the sames fragment when I select "item 1" and then "item 0"... So the number of fragment increase.
How can ViewPager remove theses fragments when its container fragment execute onDestroy ?
My code
MainActivity
public class Main extends SherlockFragmentActivity {
//Nombre de los elementos de la lista
private String[] mTitles;
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
private ListView mDrawerList;
private int currentPosition;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main_navigation_drawer);
//Inicialmente no hay ninguna opcion
currentPosition = -1;
mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
mDrawerList = (ListView)findViewById(R.id.left_drawer);
mDrawerToggle = new ActionBarDrawerToggle(
this,
mDrawerLayout,
R.drawable.ic_drawer,
R.string.drawer_open,
R.string.drawer_close) {
/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
// creates call to onPrepareOptionsMenu()
supportInvalidateOptionsMenu();
}
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
// creates call to onPrepareOptionsMenu()
supportInvalidateOptionsMenu();
}
};
mTitles = getResources().getStringArray(R.array.navigation_drawer_options);
//Asignamos el Adapter
mDrawerList.setAdapter(new ArrayAdapter<String>(this,R.layout.drawer_list_item, mTitles));
//Asignamos el listener
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
mDrawerLayout.setDrawerListener(mDrawerToggle);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
if (savedInstanceState == null) {
selectItem(0);
}
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectItem(position);
}
}
/** Swaps fragments in the main content view */
private void selectItem(int position) {
// Create a new fragment and specify the planet to show based on position
if(currentPosition != position){
//Solo hacemos remplazo de fragment si la opcion selecionada no es la misma
//que la que esta ya en pantalla
Fragment fragment = null;
String fragmentName = "";
boolean attach = true;
switch (position) {
case 0:
fragmentName = PagerFragment.class.getSimpleName();
fragment = getSupportFragmentManager().findFragmentByTag(fragmentName);
if(fragment == null) {
fragment = new PagerFragment();
attach = false;
}
break;
case 1:
fragmentName = Map1Fragment.class.getSimpleName();
fragment = getSupportFragmentManager().findFragmentByTag(fragmentName);
if(fragment == null) {
fragment = new Map1Fragment();
attach = false;
}
break;
default:
throw new IllegalArgumentException("Posicion no valida");
}
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
if(!attach){
transaction.replace(R.id.content_frame, fragment);
}else{
transaction.attach(fragment);
}
transaction.commit();
}
currentPosition = position;
// Highlight the selected item, update the title, and close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerLayout.closeDrawer(mDrawerList);
}
}
Fragment with ViewPager
public class PagerFragment extends SherlockFragment{
private ViewPager viewPager;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d("PagerFragment", "onCreateView");
return inflater.inflate(R.layout.application_tus, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.d("PagerFragment", "onViewCreated");
viewPager = (ViewPager) view.findViewById(R.id.viewpager);
viewPager.setAdapter(new ViewPagerAdapter(getSherlockActivity(), getFragmentManager()));
TitlePageIndicator titleIndicator = (TitlePageIndicator)view.findViewById(R.id.titles_viewpager);
titleIndicator.setViewPager(viewPager,0);
}
}
FragmentStatePagerAdapter
public class ViewPagerAdapter extends FragmentStatePagerAdapter{
public static final int NUM_PAGES = 2;
public static final int [] titles = { R.string.st1, R.string.st2};
private Context context;
public ViewPagerAdapter(Context context, FragmentManager fragmentManager) {
super(fragmentManager);
this.context = context;
}
#Override
public Fragment getItem(int position) {
Log.d("ViewPagerAdapter", "GetItem(" + position+")");
switch (position) {
case 0:
return new FavoritesFragment();
case 1:
return new LinesFragment();
default:
throw new IllegalArgumentException("Error");
}
}
#Override
public int getCount() {
return NUM_PAGES;
}
#Override
public CharSequence getPageTitle(int position) {
return context.getString(titles[position]);
}
}
I finally resolved my problem.
When i create the FragmentStatePagerAdapter I used new ViewPagerAdapter(getSherlockActivity(), getFragmentManager()). I finally used getChildFragmentManager() and it's work!
Related
I have a Nav drawer and view pager in an activity.
The problem is the screens overlap. When I click on a different item in the nav drawer, it changes to the appropriate screen but the view pager stays the same. In the view pager getItem(), i would call a fragment with Fragment.newInstance(int index). I tried changing the getItem() method in the view pager to use the same code as the nav drawer and replace the current fragment, however that gives me " java.lang.IllegalStateException: Can't change container ID of fragment". I tried getting rid of the ID of the items by removing the fragment and committing the change. It didn't fix the error.
Any suggestions or help would be greatly appreciated.
public class MainActivity extends FragmentActivity {
private String[] titles;
private ListView drawerList;
private DrawerLayout drawerLayout;
private ActionBarDrawerToggle drawerToggle;
private int currentPosition = 0;
private ShareActionProvider shareActionProvider;`
MyPagerAdapter myPagerAdapter;
ViewPager pager;
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//code to run when the item gets clicked
selectItem(position);
}
}
;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
titles = getResources().getStringArray(R.array.options);
drawerList = (ListView) findViewById(R.id.drawer);
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
myPagerAdapter = new MyPagerAdapter(this.getSupportFragmentManager());
//find view pager
pager = (ViewPager) findViewById(R.id.viewPager);
//set view pager adapter
pager.setAdapter(myPagerAdapter);
//item user clicks on is highlighted
//with simple_list_item_activated_1
drawerList.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_activated_1, titles));
drawerList.setOnItemClickListener(new DrawerItemClickListener());
//if mainactivity is newly created,
//use selectItem() to display HomeFragment
if (savedInstanceState != null) {
currentPosition = savedInstanceState.getInt("position");
setActionBarTitle(currentPosition);
} else {
selectItem(0);
}
//create the actionbarToggle
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout,
R.string.open_drawer, R.string.close_drawer) {
//called when a drawer has settleed in a completely closed state
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
invalidateOptionsMenu();
}
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
invalidateOptionsMenu();
}
};
drawerLayout.setDrawerListener(drawerToggle);
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
FragmentManager fragMan = getSupportFragmentManager();
Fragment fragment = fragMan.findFragmentById(R.id.content_frame);
if (fragment instanceof HomeFragment) {
currentPosition = 0;
}
if (fragment instanceof EducationFragment) {
currentPosition = 1;
}
if (fragment instanceof TechnicalSkillsFragment) {
currentPosition = 2;
}
if (fragment instanceof WorkExpFragment) {
currentPosition = 3;
}
setActionBarTitle(currentPosition);
drawerList.setItemChecked(currentPosition, true);
}
}
);
}
private Fragment selectItem(int position) {
//currentPosition for savedInstanceState
currentPosition = position;
Fragment fragment = null;
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction ft = fragmentManager.beginTransaction();
if(fragment !=null){
ft.remove(fragment).commit();
fragmentManager.executePendingTransactions();
}
switch (position) {
case 1:
fragment = new EducationFragment();
break;
case 2:
fragment = new TechnicalSkillsFragment();
break;
case 3:
fragment = new WorkExpFragment();
break;
default:
fragment = new HomeFragment();
break;
}
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(null);
ft.commit();
//set title and close the drawer
if (drawerLayout.isDrawerOpen(drawerList)) {
setActionBarTitle(position);
drawerLayout.closeDrawer(drawerList);
}
return fragment;
}
public class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
return selectItem(position);
}
#Override
public int getCount() {
return 4;
}
I have a drawer navigationview on the left connects to different fragments with different viewpagers. The structure is as followed.
MainActivity
Drawer NavigationView
| Fragment A -- ViewPagerA ----Tab1 - Fragment1
Tab2 - Fragment2
| Tab3 - Fragment3
| Fragment B -- ViewPagerB ----Tab1 - Fragment4
Tab2 - Fragment5
| Tab3 - Fragment6
Fragment1-6 are list view fragments.
The problem is when I switch from Fragment A to Fragment B, viewpager will cache the content of list view from Fragment1 and try to show the cached content to the adapter of Fragment4. So that it always shows wrong information when the first time I switch fragments from navigation drawer.
My Code:
MainActivity:
public class MainActivity extends Activity {
#InjectView(R.id.navigation_view) public NavigationView mNavigationView;
#InjectView(R.id.drawerLayout) public DrawerLayout mDrawerLayout;
//......Layout injections..............///
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDrawerToggle = new ActionBarDrawerToggle(this,mDrawerLayout, mToolbar,R.string.app_name,
R.string.app_name){
/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
}
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
};
}
public void setUpToggle()
{
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
// This method will trigger on item Click of navigation menu
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
if (menuItem.isChecked()) menuItem.setChecked(false);
else menuItem.setChecked(true);
//Closing drawer on item click
mDrawerLayout.closeDrawers();
switch (menuItem.getItemId()) {
case R.id.a_drawer:
startFragment(FragmentA.newInstance());
return true;
case R.id.b_drawer:
startFragment(FragmentB.newInstance());
return true;
default:
Toast.makeText(getApplicationContext(),"More things need to be added",Toast.LENGTH_SHORT).show();
return true;
}
}
});
mDrawerLayout.setDrawerListener(mDrawerToggle);
mDrawerToggle.syncState();
}
}
Fragment A/B (Exactly the same structures and layouts)
public class TabFragment extends Fragment {
public static TabLayout tabLayout;
public static ViewPager viewPager;
public static int int_items = n; //n is any positive integer
private Context mContext;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
/**
*Inflate tab_layout and setup Views.
*/
View tabView = inflater.inflate(R.layout.fragment_tab,null);
tabLayout = (TabLayout) tabView.findViewById(R.id.tabs);
viewPager = (ViewPager) tabView.findViewById(R.id.viewpager);
viewPager.setAdapter(new MyAdapter(getChildFragmentManager()));
tabLayout.post(new Runnable() {
#Override
public void run() {
tabLayout.setupWithViewPager(viewPager);
}
});
return tabView;
}
class MyAdapter extends FragmentStatePagerAdapter{
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position)
{
switch (position){
case 0 : return new Fragment1();//or Fragment4 5 6 here
case 1 : return new Fragment2();
case 2 : return new Fragment3();
default:return new Fragment1();
}
}
#Override
public int getCount() {
return int_items;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position){
case 0 :
return "F1";
case 1 :
return "F2";
case 2 :
return "F3";
}
return null;
}
}
Fragment 1 - 6 :
public class TabFocusFragmentextends extends Fragment
implements LoaderManager.LoaderCallbacks<Cursor>
{
private TabFocusAdapter mAdapter;
private List<E> mList;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadData();// never been executed,:(
setHasOptionsMenu(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_tab_focus, container, false);
loadData();
setupRecyclerView();
return view;
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onLoadMore() {
if(NeedLoad)
loadData();
}
private void loadData() {
//RequestData
……
}
private void setupRecyclerView() {
…...
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(mActivity, ContentProvider.createUri(E.class, null),
null, null, null, null);
}
#Override //fragment starts here, why??
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if (loadedList.size() > 0) {
//crashes here …...
if (!fullPacketLoaded) {
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
If new fragment list adapter doesn't have an appropriate to show previous content, it will crash.
Based on this question, if you have a better solution for the question down below as well? Why is Tablayout and Viewpager crashing with NullpointerException when I start a fragment with LoaderManager from TabFragment?
Finally fixed.
In my onCreate() method of which fragment implemented LoaderManager, I did this
getLoaderManager().initLoader(0, null, this);
if(!getLoaderManager().getLoader(0).isReset()) {
getLoaderManager().restartLoader(0, null, this);
}
It works when new loader was not actived properly.
As mentioned in my previous question I had some problem with showing Fragments inside a ViewPager after opening another Fragment from one of the Fragments inside the ViewPager.
I somehow managed to resolve the problem by using add() in the FragmentTransaction. Unfortunately this creates another problem:
I am using the ActionBar in my app. When I am selecting the same menu item twice I encounter the same problem as before, it doesn't show any Fragments inside the ViewPager.
Home Activity Code(where action bar on click events are call)
public class HomePageActivity extends SherlockFragmentActivity implements ICallback {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private SherlockActionBarDrawerToggle mDrawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
private String[] mChampionsMenuItems;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.Theme_Sherlock);
setContentView(R.layout.activity_home_page);
mTitle = mDrawerTitle = getTitle();
mChampionsMenuItems = getResources().getStringArray(R.array.champions_array);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
mDrawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, mChampionsMenuItems));
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setBackgroundDrawable(getResources().getDrawable(R.color.navy_blue));
getSupportActionBar().setDisplayShowTitleEnabled(false);
mDrawerToggle = new SherlockActionBarDrawerToggle(this, mDrawerLayout, R.drawable.menu_icon, R.string.drawer_open, R.string.drawer_close) {
public void onDrawerClosed(View view) {
getSupportActionBar().setTitle(mTitle);
supportInvalidateOptionsMenu();
}
public void onDrawerOpened(View drawerView) {
getSupportActionBar().setTitle(mDrawerTitle);
supportInvalidateOptionsMenu();
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
if (savedInstanceState == null) {
onFragmentChange(new HomeActivityFragment(), true);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
switch (item.getItemId()) {
default: return super.onOptionsItemSelected(item);
}
}
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectItem(position);
}
}
private void selectItem(int position) {
switch (position) {
case 0:
onFragmentChange(new Fragment1(), false);
break;
case 1:
onFragmentChange(new Fragment2(), false);
break;
case 2:
onFragmentChange(new MyPointFragment3(), false);
break;
case 3:
// onFragmentChange(new HomeActivityFragment(), true);
break;
case 4:
onFragmentChange(new QueriesFragment(), false);
break;
case 5:
onFragmentChange(new GalleryFragment(), false);
break;
default:
break;
}
mDrawerList.setItemChecked(position, true);
mDrawerLayout.closeDrawer(mDrawerList);
}
#Override
public void setTitle(CharSequence title) {
mTitle = title;
getSupportActionBar().setTitle(mTitle);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public void onFragmentChange(Fragment fragment, boolean flag) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(R.id.content_frame, fragment, fragment.getClass().getName());
transaction.commit();
}
}
This is the Fragment which contains the ViewPager:
public class Fragment1 extends Fragment implements OnClickListener {
ICallback callback;
private LinearLayout headerContainer;
private ImageView headerLogo;
private TextView headerName;
private Button menuBarButton;
MyAdapter adapter;
ViewPager pager;
ActionBar actionBar;
private Button progOverview, progStr, bonusPoint;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof ICallback) {
this.callback = (ICallback) activity;
}
actionBar = activity.getActionBar();
actionBar.show();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = setUpView(inflater, container);
return rootView;
}
private View setUpView(LayoutInflater inflater, ViewGroup container) {
View rootView = inflater.inflate(R.layout.fragment_about_champions_club, container, false);
headerContainer = (LinearLayout) rootView.findViewById(R.id.second_top_header);
headerContainer.setBackgroundColor(getResources().getColor(R.color.prog_str_blue));
headerLogo = (ImageView) rootView.findViewById(R.id.header_logo);
headerLogo.setBackgroundResource(R.drawable.about_champions_ticon);
headerName = (TextView) rootView.findViewById(R.id.header_name);
headerName.setText(R.string.about_champ_title);
adapter = new MyAdapter(getFragmentManager());
pager = (ViewPager) rootView.findViewById(R.id.pager);
pager.setAdapter(adapter);
return rootView;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
// Restore last state for checked position.
}
}
}
}
This is one of the Fragments inside the ViewPager:
public class ProgramOverViewFragment extends Fragment {
ICallback callback;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof ICallback) {
this.callback = (ICallback) activity;
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_program_overview, container, false);
TextView termsAndCond = (TextView) rootView.findViewById(R.id.terms_and_condition_button);
termsAndCond.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content_frame, fragment);
fragment.setRetainInstance(true);
transaction.addToBackStack(null);
transaction.commit();
}
});
return rootView;
}
}
My FragmentStatePagerAdapter:
public class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int index) {
switch (index) {
case 0: return new ProgramOverViewFragment();
case 1: return new ProgramStructureFragment();
case 2: return new BonusPointFragment();
}
return null;
}
#Override
public int getCount() {
return 3;
}
}
Thanks for your help!
What do you want to do exactly? Are you trying to replace a Fragment inside the ViewPager? Or are you trying to replace a Fragment inside a Fragment inside the ViewPager? Or are you trying to do something different altogether? I can only give you an accurate solution if you explain what you are trying to do in detail. Anyway here is what I am guessing might be wrong:
I think your problem is that you use the wrong FragmentManager. There are multiple different FragmentManagers, but essentially there are two cases:
You want to add/replace/remove a Fragment from an Activity
You want to add/replace/remove a Fragment from another Fragment
As long as I don't see your layout files I can't be sure which of those two options fits your situation.
Solution if you want to replace a Fragment inside of another Fragment
If you want to perform a FragmentTransaction on a Fragment inside of another Fragment, then you need to use the child FragmentManager! You can use the child FragmentManager inside a Fragment like this:
FragmentManager fragmentManager = getChildFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content_frame, fragment);
fragment.setRetainInstance(true);
transaction.addToBackStack(null);
transaction.commit();
As you can see you just need to use getChildFragmentManager() instead of getSupportFragmentManager()
As I already said, without any further information about your situation I cannot give you a more accurate answer. So please try to explain what you want to do as best as you can to me and I'm confident we can solve this.
Finally i found what i did wrong in my code :
i'm using this below code for setting adapter for view Pager inside a fragment :
adapter = new MyAdapter(getFragmentManager());
pager = (ViewPager) rootView.findViewById(R.id.pager);
pager.setAdapter(adapter);
and by replacing getFragmentManager() to getChildFragmentManager() we resolve this problem. As per my understanding i'm using view pager inside a fragment that's why i have to use getChildFragment manager to store transitions of my viewPager.
Might this help someone and this question is still open for better solutions.
I'm trying to use a NavigationDrawer with FragmentStatePagerAdapter for the navigation of my app. The idea is that when clicking on an item of the NavigationDrawer a new fragment opens with two tabs in it.
My problem is that I can't make it work correctly. When clicking on an item of the NavigationDrawer, instead of two tabs I get four, then six, ...
This problem can be solved with actionBar.removeAllTabs(), but my main problem is that when I come back on a previous fragment by re-clicking on the item of the NavigationDrawer (fragment 1 -> fragment 2 -> fragment 1), I got an empty fragment.
I tried to solve this problem by make some changes according to what's stated on other pages, but I didn't succeed in making it work.
Any help would be appreciated, thank you!
Here is the class managing my main fragment:
public class FragmentMultiTab extends SherlockFragment {
private MyVariables mk;
private ActionBar actionBar;
private ViewPager viewPager;
private View rootView;
private int i;
#Override
public View onCreateView(final LayoutInflater inflater,
final ViewGroup container, final Bundle savedInstanceState) {
final int[] fragment = { R.layout.fragment1, R.layout.fragment2,
R.layout.fragment3 };
final int[] pager = { R.id.pager1, R.id.pager2, R.id.pager3 };
this.mk = new MyVariables(this.getArguments());
i = this.mk.getInt("INDEX");
this.rootView = inflater.inflate(fragment[i], container, false);
viewPager = (ViewPager) this.rootView.findViewById(pager[i]);
viewPager.setOnPageChangeListener(onPageChangeListener);
viewPager.setAdapter(new ViewPagerAdapter(getFragmentManager()));
viewPager.getAdapter().notifyDataSetChanged();
addActionBarTabs();
return rootView;
}
private final ViewPager.SimpleOnPageChangeListener onPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
super.onPageSelected(position);
actionBar.setSelectedNavigationItem(position);
}
};
private void addActionBarTabs() {
actionBar = getSherlockActivity().getSupportActionBar();
final String[][] tabTitle = {{"Tab 1","Tab 3","Tab 5" },{"Tab 2","Tab 4",
"Tab 6" } };
for (int k = 0; k < 2; k++) {
ActionBar.Tab tab = actionBar.newTab().setText(tabTitle[k][i])
.setTabListener(tabListener);
actionBar.addTab(tab);
}
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
}
private final ActionBar.TabListener tabListener = new ActionBar.TabListener() {
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
};
}
Here is the ViewPager used
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
final int PAGE_COUNT = 2;
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int arg0) {
switch (arg0) {
case 0:
FragmentTab1 fragmenttab1 = new FragmentTab1();
return fragmenttab1;
case 1:
FragmentTab2 fragmenttab2 = new FragmentTab2();
return fragmenttab2;
}
return null;
}
#Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return PAGE_COUNT;
}
}
My fragments have the following structure:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v4.view.ViewPager
android:id="#+id/pager1"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</android.support.v4.view.ViewPager>
</RelativeLayout>
And finally here is my MainActivity:
public class MainActivity extends SherlockFragmentActivity {
DrawerLayout mDrawerLayout;
ListView mDrawerList;
ActionBarDrawerToggle mDrawerToggle;
MenuListAdapter mMenuAdapter;
FragmentMultiTab fragment1 = new FragmentMultiTab();
FragmentMultiTab fragment2 = new FragmentMultiTab();
FragmentMultiTab fragment3 = new FragmentMultiTab();
private final MyVariables mk = new MyVariables();
private int currentPosition;
#Override
public void onConfigurationChanged(final Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggles
this.mDrawerToggle.onConfigurationChanged(newConfig);
}
// The click listener for ListView in the navigation drawer
private class DrawerItemClickListener implements
ListView.OnItemClickListener {
#Override
public void onItemClick(final AdapterView<?> parent, final View view,
final int position, final long id) {
MainActivity.this.selectItem(position);
}
}
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_main);
currentPosition = -1;
// Locate DrawerLayout in activity_main.xml
this.mDrawerLayout = (DrawerLayout) this
.findViewById(R.id.drawer_layout);
// Locate ListView in activity_main.xml
this.mDrawerList = (ListView) this.findViewById(R.id.listview_drawer);
// Set a custom shadow that overlays the main content when the drawer
// opens
this.mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow,
GravityCompat.START);
// Pass results to MenuListAdapter Class
this.mMenuAdapter = new MenuListAdapter(this);
// Set the MenuListAdapter to the ListView
this.mDrawerList.setAdapter(this.mMenuAdapter);
// Capture button clicks on side menu
this.mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
// Enable ActionBar app icon to behave as action to toggle nav drawer
this.getSupportActionBar().setHomeButtonEnabled(true);
this.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// ActionBarDrawerToggle ties together the the proper interactions
// between the sliding drawer and the action bar app icon
this.mDrawerToggle = new ActionBarDrawerToggle(this,
this.mDrawerLayout, R.drawable.ic_drawer, R.string.drawer_open,R.string.drawer_close) {
#Override
public void onDrawerClosed(final View view) {
// TODO Auto-generated method stub
super.onDrawerClosed(view);
}
#Override
public void onDrawerOpened(final View drawerView) {
// TODO Auto-generated method stub
super.onDrawerOpened(drawerView);
}
};
this.mDrawerLayout.setDrawerListener(this.mDrawerToggle);
if (savedInstanceState == null) {
this.selectItem(0);
}
this.mk.setVariables(this);
}
#Override
public boolean onCreateOptionsMenu(final Menu menu) {
this.getSupportMenuInflater().inflate(R.menu.action_bar_main, menu);
this.getActionBar().setDisplayHomeAsUpEnabled(true);
return true;
}
#Override
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if (this.mDrawerLayout.isDrawerOpen(this.mDrawerList)) {
this.mDrawerLayout.closeDrawer(this.mDrawerList);
} else {
this.mDrawerLayout.openDrawer(this.mDrawerList);
}
default:
return super.onOptionsItemSelected(item);
}
}
#Override
protected void onPostCreate(final Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
this.mDrawerToggle.syncState();
}
private void selectItem(final int position) {
final FragmentTransaction ft = this.getSupportFragmentManager()
.beginTransaction();
if (currentPosition != position)
// Locate Position
switch (position) {
case 0:
this.mk.addInt("INDEX", 0);
this.mk.addBoolean("START", false);
this.fragment1.setArguments(this.mk.getArgs());
ft.replace(R.id.content_frame, this.fragment1);
break;
case 1:
this.mk.addInt("INDEX", 1);
this.fragment2.setArguments(this.mk.getArgs());
ft.replace(R.id.content_frame, this.fragment2);
break;
case 2:
this.mk.addInt("INDEX", 2);
this.fragment3.setArguments(this.mk.getArgs());
ft.replace(R.id.content_frame, this.fragment3);
break;
}
currentPosition = position;
ft.commit();
this.mDrawerList.setItemChecked(position, true);
// Close drawer
this.mDrawerLayout.closeDrawer(this.mDrawerList);
}
}
I'd suggest using the ViewPagerIndicator instead of the standard ActionBar Tabs (they have some issues with regards to being converted into dropdown menus in some cases. The interface is quite simply (you just hook your viewpagerindicator to a viewpager), and you'll probably solve your issue as well.
I have a Main Drawer activity which loads my fragments when a drawer item is selected. The fragment that is laoded contains a tabhost which hosts multiple fragments so you can switch to via tabs.
Before Tabs I had a fragment with a bunch of butons that when clicked, replaced the current fragment with a new fragment. The fragments all have listviews in them, and when you click an item replaced the current listview fragment with another fragment.
My problem is when I placed all my fragments into a tabhost the ArticleOnSelected no longer works, and force closes my app when ever an item is actually selected form the list view. Here is an example of one of the FC errors:
03-02 16:40:34.121 9066-9066/com.beerportfolio.beerportfoliopro E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.IllegalArgumentException: No view found for id 0x7f09008c (com.beerportfolio.beerportfoliopro:id/main) for fragment BreweryPage2{41ba3478 #2 id=0x7f09008c}
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:919)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1467)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:5789)
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:1027)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:843)
at dalvik.system.NativeStart.main(Native Method)
I see the problem is with the view, and I think it can not access the main framelayout from the layout which holds all the fragments with the navigation drawer.
My MainDrawer2 class is what opens first and is where the drawer and fragments are loaded into. The code is:
public class MainDrawer2 extends FragmentActivity
{
private static final String EXTRA_NAV_ITEM = "extraNavItem";
private static final String STATE_CURRENT_NAV = "stateCurrentNav";
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
private NavDrawerListAdapter mDrawerAdapter;
private ListView mDrawerList;
private CharSequence mTitle;
private CharSequence mDrawerTitle;
private MainNavItem mCurrentNavItem;
public static Intent createLaunchFragmentIntent(Context context, MainNavItem navItem)
{
return new Intent(context, MainDrawer2.class)
.putExtra(EXTRA_NAV_ITEM, navItem.ordinal());
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);
mTitle = mDrawerTitle = getTitle();
mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
mDrawerList = (ListView)findViewById(R.id.drawer);
getActionBar().setDisplayHomeAsUpEnabled(true);
enableHomeButtonIfRequired();
mDrawerAdapter = new NavDrawerListAdapter(getApplicationContext());
mDrawerList.setAdapter(mDrawerAdapter);
mDrawerList.setOnItemClickListener(new ListView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
displayNavFragment((MainNavItem)parent.getItemAtPosition(position));
}
});
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_drawer, R.string.app_name, R.string.app_name)
{
public void onDrawerClosed(View view)
{
getActionBar().setTitle(mTitle);
invalidateOptionsMenu();
}
public void onDrawerOpened(View drawerView)
{
getActionBar().setTitle(mDrawerTitle);
invalidateOptionsMenu();
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
if(getIntent().hasExtra(EXTRA_NAV_ITEM)){
MainNavItem navItem = MainNavItem.values()
[getIntent().getIntExtra(EXTRA_NAV_ITEM,
MainNavItem.STATISTICS.ordinal())];
displayNavFragment(navItem);
}
else if(savedInstanceState != null){
mCurrentNavItem = MainNavItem.values()
[savedInstanceState.getInt(STATE_CURRENT_NAV)];
setCurrentNavItem(mCurrentNavItem);
}
else{
displayNavFragment(MainNavItem.STATISTICS);
}
}
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void enableHomeButtonIfRequired()
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH){
getActionBar().setHomeButtonEnabled(true);
}
}
#Override
public void setTitle(CharSequence title)
{
mTitle = title;
getActionBar().setTitle(mTitle);
}
#Override
protected void onPostCreate(Bundle savedInstanceState)
{
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggles
mDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putInt(STATE_CURRENT_NAV, mCurrentNavItem.ordinal());
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
/*
#Override
public boolean onPrepareOptionsMenu(Menu menu)
{
// if nav drawer is opened, hide the action items
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
}
*/
private void displayNavFragment(MainNavItem navItem)
{
if(navItem == mCurrentNavItem){
return;
}
Fragment fragment = Fragment.instantiate(this,
navItem.getFragClass().getName());
if(fragment != null){
getSupportFragmentManager().beginTransaction()
.replace(R.id.main, fragment)
.commit();
setCurrentNavItem(navItem);
}
}
private void setCurrentNavItem(MainNavItem navItem)
{
int position = navItem.ordinal();
// If navItem is in DrawerAdapter
if(position >= 0 && position < mDrawerAdapter.getCount()){
mDrawerList.setItemChecked(position, true);
}
else{
// navItem not in DrawerAdapter, de-select current item
if(mCurrentNavItem != null){
mDrawerList.setItemChecked(mCurrentNavItem.ordinal(), false);
}
}
mDrawerLayout.closeDrawer(mDrawerList);
setTitle(navItem.getTitleResId());
mCurrentNavItem = navItem;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if(mDrawerLayout.isDrawerOpen(mDrawerList)) {
mDrawerLayout.closeDrawer(mDrawerList);
}
else {
mDrawerLayout.openDrawer(mDrawerList);
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void goToSearch(MenuItem item){
//go to search page
Fragment Fragment_one;
FragmentManager man= getSupportFragmentManager();
FragmentTransaction tran = man.beginTransaction();
Fragment_one = new Search();
tran.replace(R.id.main, Fragment_one);//tran.
tran.addToBackStack(null);
tran.commit();
}
}
The default fragment which is loaded is the fragment which holds my tabhost and creates the tabs:
public class StatisticsTab extends Fragment {
private FragmentTabHost mTabHost;
//Mandatory Constructor
public StatisticsTab() {
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_tabs,container, false);
mTabHost = (FragmentTabHost)rootView.findViewById(android.R.id.tabhost);
mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.realtabcontent);
mTabHost.addTab(mTabHost.newTabSpec("Basic").setIndicator("Basic"),
StatisticsPage.class, null);
mTabHost.addTab(mTabHost.newTabSpec("Brewery").setIndicator("Brewery"),
BreweryStatistics.class, null);
mTabHost.addTab(mTabHost.newTabSpec("Style").setIndicator("Style"),
StyleStatistics.class, null);
mTabHost.addTab(mTabHost.newTabSpec("Taste").setIndicator("Taste"),
TasteStatisticsPage.class, null);
return rootView;
}
}
If I click on an item in my tab and bring up the listview like this:
It gives me the FC I posted above. The code for this fragment is:
public class BreweryStatistics extends Fragment implements GetBreweryStatisticsJSON.OnArticleSelectedListener {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.brewery_statistics_layout, container, false);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
String userName = prefs.getString("userName", null);
String userID = prefs.getString("userID", null);
String url = "myURL";
//async task to get beer taste tag percents
GetBreweryStatisticsJSON task = new GetBreweryStatisticsJSON(getActivity());
task.setOnArticleSelectedListener(this);
task.execute(url);
// Inflate the layout for this fragment
return v;
}
#Override
public void onArticleSelected(String bID){
//code to execute on click
Fragment Fragment_one;
FragmentManager man= getFragmentManager();
FragmentTransaction tran = man.beginTransaction();
Fragment_one = new BreweryPage2();
final Bundle bundle = new Bundle();
bundle.putString("breweryIDSent", bID);
Fragment_one.setArguments(bundle);
tran.replace(R.id.main, Fragment_one);//tran.
tran.addToBackStack(null);
tran.commit();
}
}
And when that onArticleSelected above is executed it does not load the new fragment. In theory what should happen the Fragment that holds the tabhost StatisticsTab should be replaced with the new Fragment in the OnArticleSelected