FragmentStatePagerAdapter getItem method is not called after orientation was changed - android

I have activity and 3 fragments. I use PagerSlidingTabStrip for suport tabs. Adapter:
public class MyPagerAdapter extends FragmentStatePagerAdapter {
...
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new Fragment1();
case 1:
return new Fragment2();
case 2:
return new Fragment3();
}
return null;
}
...
}
Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final PagerSlidingTabStrip tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
final ViewPager pager = (ViewPager) findViewById(R.id.pager);
final MyPagerAdapter pagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
pager.setAdapter(pagerAdapter);
pager.setCurrentItem(1);
final int pageMargin = (int) applyDimension(COMPLEX_UNIT_DIP, 4, getResources().getDisplayMetrics());
pager.setPageMargin(pageMargin);
tabs.setViewPager(pager);
tabs.setOnPageChangeListener(listener);
tabs.setTextColor(Color.rgb(255, 255, 255));
tabs.setIndicatorColor(Color.parseColor("#FF96AA39"));
}
When app is loading first time getItem is executed 3 times. What is correct. First fragment is shown. Then after change roration getItem for first fragment is not executed. But when I switch to secons or third one getItem is executed.
Could you help me why getItem is not called for first fragment when screen orientation was changed?

Related

how to set the starting tab in tab layout with Toolbar?

I'm sorry I am not fluent in English.
I wanna change the starting fragment in tab layout.
There is a value from another activity that gave with intent.
so I just want to start tab layout's fragment with my selection.
This is main activity's onCreate()
public class MainActivity extends AppCompatActivity {
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
}
And this is the code of changing in fragment
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch(position)
{
case 0:
return new TotalFragment();
case 1:
return new StatsFragment();
case 2:
return new FeedbackFragment();
case 3:
return new ManageFragment();
}
return null;
}
#Override
public int getCount() {
return 4;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "TOTAL";
case 1:
return "STATS";
case 2:
return "FEEDBACK";
case 3:
return "MANAGE";
}
return null;
}
}
}
Jisu Lee, we can set the starting tab in tab layout with the help of setCurrentItem() to viewpager.
We can set it by two types :
Example :
1.Simple setting tab:
Explation : Set the currently selected page. If the ViewPager has already been through its first layout with its current adapter there will be a smooth animated transition between the current item and the specified item.
viewPager.setCurrentItem(1);
2.For enableing smoothScroll :
Secand parameter "True" to smoothly scroll to the new item, "false" to transition immediately
viewPager.setCurrentItem(1, true);
Or for getting the CurrentItem we have : viewPager.getCurrentItem();
It will return the starting tab index (int).
mViewPager.setCurrentItem({index you want}, true);

Call fragment function over activity

I have a TabLayout with 3 tab.They are a fragment.
Test.java->PagerAdapter.java->TabFragment1+TabFragment2+TabFragment3
I want to call TabFragment1.helloworld() function. How can i call this function? Thanks.
Test.java created 3 tabs in below
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.addTab(tabLayout.newTab().setText("tab1"));
tabLayout.addTab(tabLayout.newTab().setText("tab2"));
tabLayout.addTab(tabLayout.newTab().setText("tab3"));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
viewPager.setOffscreenPageLimit(3);
final PagerAdapter adapter = new PagerAdapter
(getSupportFragmentManager(),
tabLayout.getTabCount());
viewPager.setAdapter(adapter);
PagerAdapter.java
public class PagerAdapter extends FragmentStatePagerAdapter {
int mNumOfTabs;
public PagerAdapter(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
TabFragment1 tab1 = new TabFragment1();
return tab1;
case 1:
TabFragment2 tab2 = new TabFragment2();
return tab2;
case 2:
TabFragment3 tab3 = new TabFragment3();
return tab3;
default:
return null;
}
}
#Override
public int getCount() {
return mNumOfTabs;
}
}
You can access the desired fragment's method through your PagerAdapter:
((TabFragment1)adapter.getItem(0)).helloworld();
It's a bit trickier than usual with ViewPagers, because you can't use the preferred findFragmentByTag() method. Here's something you could try - it's untested, but should be ok:
Create an interface, which all Fragments in your ViewPager implement:
public interface ViewPagerFragmentBase {
void callCommonMethod(int code);
}
Implement it in all your ViewPager Fragments:
public FragmentOne implements ViewPagerFragmentBase {
#Override
public void callCommonMethod(int code) {
if (code == 1) {
//Run code in this Fragment
}
}
public FragmentTwo implements ViewPagerFragmentBase {
#Override
public void callCommonMethod(int code) {
if (code == 2) {
//Run code in this Fragment
}
}
Inside your Activity class, grab all Fragments currently in your Adapter, then cycle through each one, calling the callCommonMethod() along with a code which indicates the Fragment you are trying to reach:
public class MainActivity extends AppCompatActivity {
private void callCommonMethodInFragments(int code) {
for (int i = 0; i < viewPagerAdapter.getCount(); i++) {
((ViewPagerFragmentBase)viewPagerAdapter.getItem(i)).callCommonMethod(code);
}
}
//To call it...
callCommonMethodInFragments(1); //This will run the method in FragmentOne only
}
If the code matches the one in the Fragment you are trying to reach, then the method will run.
Something else you could also try though is an EventBus - this would allow you to achieve your goal more directly, and with less typing: https://github.com/greenrobot/EventBus
To call fragment method from parent activity:
ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
fragment.callFunction();
I had the same issue, and this worked for me:
You have to add the fragments via your adapter and then you can access the fragment functions:
myViewPager = (ViewPager) findViewById(R.id.viewpager);
MyAdapterClass adapter = new MyAdapterClass(getSupportFragmentManager());
adapter.addFragment(new TabOneFragment(), "");
adapter.addFragment(new TabTwoFragment(), "");
adapter.addFragment(new TabThreeFragment(), "");
myViewPager.setAdapter(adapter);
myTabLayout = (TabLayout) findViewById(R.id.tab_layout);
myTabLayout.setupWithViewPager(myViewPager);
// to access fragment functions:
TabOneFragment tabOneFragment = (TabOneFragment) adapter.getItem(0);
tabOneFragment.functionWhatSoEver();

getItem in FragmentPagerAdapter not working as expected

I have the below code in my app.
From my understanding I expect that after Main activity is loaded getItem from Tab Adapter should be called with index: 1 as it is set as tab-1 .setTabListener(this), 1,true);
But instead of it getItem gets called twice first with index: 0 and then index: 1. Why is that can anyone explain?
//Main activity code:
#Override
protected void onCreate(final Bundle savedInstanceState) {
…
// Tabs Initilization
viewPager = (ViewPager) findViewById(R.id.TabHandler);
actionBar = getActionBar();
mAdapter = new TabsAdapter(getSupportFragmentManager());
actionBar.addTab(actionBar.newTab().setText(tabs[0])
.setTabListener(this), 0, false);
actionBar.addTab(actionBar.newTab().setText(tabs[1])
.setTabListener(this), 1,true);
actionBar.addTab(actionBar.newTab().setText(tabs[2])
.setTabListener(this), 2, false);
}
//And this inside the `Tab Adapter`
public class TabsAdapter extends FragmentPagerAdapter {
public TabsAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
return new ZeroViewFragment();
case 1:
return new OneViewFragment();
case 2:
return new TwoViewFragment();
}
return null;
}
#Override
public int getCount() {
return 3;
}
}
This is beacause the ViewPager loads not only the visible fragment but the left and right fragments too. So in your case the visible fragment is #0, there is not left fragment and the right fragment is #1. The result is that fragments #0 and #1 are loaded. This behavior is implemented for performance reasons because this way the ViewPager has the next fragment prepared and ready to be shown and there will be no lag when swiping between pages.

Android tabs implemented with Fragments and ViewPager

My application has 3 tabs, each represented by Fragments. There is a custom FragmentPagerAdapter which also implements ActionBar.TabListener. Initially my FragmentPagerAdapter was returning new instances of fragments in public Fragment getItem(int index) method. Also, my TabListener implementation was instantiating Fragments and showing/hiding them in the onTabSelected/onTabUnselected. Unfortunately this approach doesn't fit me well, because in this case each Fragment is actually created twice. What I want is to create it once and then just hide/show, when necessary.
For that I have instantiated my fragment earlier in the activity and passed them to the PagerAdapter:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_tabs_layout);
List<Fragment> fragments = initTabFragments();
ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
final ActionBar actionBar = getSupportActionBar();
TabsPagerAdapter pagerAdapter = new TabsPagerAdapter(this, getSupportFragmentManager(), fragments, viewPager);
viewPager.setAdapter(pagerAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
for (int tab_name : tabs) {
Tab tab = actionBar.newTab();
actionBar.addTab(tab.setText(tab_name).setTabListener(pagerAdapter));
}
...
}
private List<Fragment> initTabFragments() {
List<Fragment> fragments = new ArrayList<Fragment>(3);
fragments.add(SherlockFragment.instantiate(this, TabFragment1.class.getName()));
fragments.add(SherlockFragment.instantiate(this, TabFragment2.class.getName()));
fragments.add(SherlockFragment.instantiate(this, TabFragment3.class.getName()));
return fragments;
}
Then in the PagerAdapter I just return fragment:
#Override
public Fragment getItem(int index) {
return fragments.get(index);
}
To handle Tab selection there is the following code:
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
int position = tab.getPosition();
String tag = "android:switcher:" + viewPagerId + ":" + position;
Fragment fragment = context.getSupportFragmentManager().findFragmentByTag(tag);
switch (position) {
case 0:
if (fragment == null) {
ft.add(viewPagerId, fragments.get(0), tag);
} else {
// If it exists, simply attach it in order to show it
ft.show(fragments.get(0));
}
break;
}
case 1:
if (fragment == null) {
ft.add(viewPagerId, fragments.get(1), tag);
} else {
// If it exists, simply attach it in order to show it
ft.show(fragments.get(1));
}
break;
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
switch (tab.getPosition()) {
case 0:
ft.hide(fragments.get(0));
break;
case 1:
ft.hide(fragments.get(1));
break;
}
}
In this case each fragment is instantiated once. And the first tab is shown correctly, but when I switch between tabs second and third tabs are empty (just white background). Why?
I was trying to add fragment to a container android.R.id.content, but exception was thrown: Can't change container ID of fragment.... I found out that it is because when Fragment is returned in getItem method it is added to a viewPager container. That why I use viewPagerId when add fragment to a transaction.
Any help would be greatly appreciated.
Have a ExampleFragment class defined that extends Fragment. Something like shown below
public class ExampleFragment extends Fragment {
private View categoryView;
private ViewPager mViewPager;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
categoryView = inflater.inflate(R.layout.viewpager, container, false);
mViewPager = (ViewPager) categoryView.findViewById(R.id.pager);
return categoryView;
}
public ViewPager returnViewPager() {
return mViewPager;
}
}
main_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
tools:context=".ExampleFragmentActivity" >
<fragment
android:id="#+id/main_fragment"
android:name="somepackage.ExampleFragment"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
And then add this in the onCreate() of ExampleFragmentActivity
ExampleFragment fragment = (ExampleFragment) getSupportFragmentManager().findFragmentById(R.id.main_fragment);
mViewPager = fragment.returnViewPager();
fragmentManager = getSupportFragmentManager();

Android: "Navigation Type: Fixed Tabs + Swipe"

I'm trying to use Tabs + Swipe in an App and want to use the Navigation Type "Fixed Tabs + Swipe" which the ADT provides me when creating an Activity.
Sooo now the ADT spits out nice Code, which I slightly modified...
I completely understand the code and what's going on... But how can I teach the App to use my three Fragments instead of the stupid Dummy Frag? :(
I cannot find any tutorial which deals with the ADTs "Navigation Types"...
Thanks for your help!
public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set up the action bar.
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
// When swiping between different sections, select the corresponding
// tab. We can also use ActionBar.Tab#select() to do this if we have
// a reference to the Tab.
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
//Adding Tabs
actionBar.addTab(actionBar.newTab().setText("Tab 1").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("Tab 2").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("Tab 3").setTabListener(this));
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in
// the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab,FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabReselected(ActionBar.Tab tab,FragmentTransaction fragmentTransaction) {
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a DummySectionFragment (defined as a static inner class
// below) with the page number as its lone argument.
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
}
public static class DummySectionFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
public static final String ARG_SECTION_NUMBER = "section_number";
public DummySectionFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_dummy,container, false);
TextView dummyTextView = (TextView) rootView.findViewById(R.id.section_label);
dummyTextView.setText(Integer.toString(getArguments().getInt(ARG_SECTION_NUMBER)));
return rootView;
}
}
}
a switch-case to set the fragments is easy and makes it really clear. Let each of your fragment inflate the root view in your xml
#Override
public Fragment getItem(int index) {
Fragment fragment = null;
switch(index){
case 0:
fragment = new Fragment1();
break;
case 1:
fragment = new Fragment2();
break;
case 2:
fragment = new Fragment3();
break;
default:
break;
}
//set args if necessary (which it isn't?)
Bundle args = new Bundle();
args.putInt(ObjectFragment.ARG_OBJECT, index + 1);
fragment.setArguments(args);
//return fragment
return fragment;
}
But how can I teach the App to use my three Fragments instead of the stupid Dummy Frag?
You will notice that DummySectionFragment is referenced in getItem() of the SectionsPagerAdapter:
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a DummySectionFragment (defined as a static inner class
// below) with the page number as its lone argument.
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
return fragment;
}
If you want to use different fragments, modify getItem() to return the fragment you want, given the supplied position (0-based page number).

Categories

Resources