FragmentStatePagerAdapter - getItem
Asked Answered
G

2

2

I know there are several other posts on this topic, but I wanted to paste my code because I believe there may be an error in it that is causing my problem. My FragmentStatePagerAdapter is returning the wrong position, and I am not sure why.

Here is the code in my Main activity.

Main.java

 import android.content.Context;
    import android.content.Intent;
    import android.graphics.Typeface;
    import android.os.Bundle;
    import android.support.design.widget.TabLayout;
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentTabHost;
    import android.support.v4.content.ContextCompat;
    import android.support.v4.view.ViewPager;
    import android.support.v7.app.ActionBar;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.Toolbar;
    import android.view.LayoutInflater;
    import android.view.MenuItem;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ImageButton;
    import android.widget.ImageView;
    import android.widget.TabHost.OnTabChangeListener;
    import android.widget.TextView;
    import android.widget.Toast;

    import com.google.android.gms.common.ConnectionResult;
    import com.google.android.gms.common.GoogleApiAvailability;
    import com.google.android.gms.gcm.GoogleCloudMessaging;
    import com.microsoft.windowsazure.notifications.NotificationsManager;

    import java.util.ArrayList;

    public class Main extends AppCompatActivity {

        public static TextView txtViewHeading;
        public static TextView tab1TabBadge;
        public static TextView tab2TabBadge;
        public static TextView tab3TabBadge;
        public static TextView tab4TabBadge;
        public static TextView tab5TabBadge;
        public static Button btnBack;
        public static ImageButton btnShare;
        public static Main mainActivity;
        public static Context mainActivityContext;
        public static Boolean isVisible = false;
        private FragmentTabHost mTabHost;
        private GoogleCloudMessaging gcm;
        private ActionBar actionBar;
        private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;

        private TabGroupAdapter mTabGroupAdapter;
        private ViewPager mViewPager;

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

            // Set up Push notifications
            mainActivity = this;
            mainActivityContext = Main.this;
            NotificationsManager.handleNotifications(this, NotificationSettings.SenderId, PushHandler.class);
            registerWithNotificationHubs();

            // Set up the views for each tab - custom view used for Badge icon
            LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            // Bind the Toolbar
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);

            // Set up the ActionBar
            actionBar = getSupportActionBar();
            if (actionBar!=null) {
                actionBar.setDisplayHomeAsUpEnabled(true);
                actionBar.setHomeButtonEnabled(true);
            }

            // Create the adapter that will return a fragment for each of the primary "tabs"
            mTabGroupAdapter = new TabGroupAdapter(getSupportFragmentManager());

            // Set up the ViewPager with the sections adapter.
            mViewPager = (ViewPager) findViewById(R.id.container);
            mViewPager.setAdapter(mTabGroupAdapter);

            TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
            tabLayout.setupWithViewPager(mViewPager);

            // tab1 Tab
            View tab1TabView = inflater.inflate(R.layout.tab, null);
            ImageView tab1TabIcon = (ImageView) tab1TabView.findViewById(R.id.tabIcon);
            tab1TabIcon.setImageResource(R.drawable.tab_first);
            TextView tab1TabText = (TextView) tab1TabView.findViewById(R.id.tabText);
            tab1TabText.setText("tab1");
            tab1TabText.setTypeface(arialTypeface);
            tab1TabBadge = (TextView) tab1TabView.findViewById(R.id.tabBadge);
            tab1TabBadge.setTypeface(arialTypeface);
            tabLayout.getTabAt(0).setCustomView(tab1TabView);
            // Also set this tab as Active be default
            tabLayout.getTabAt(0).getCustomView().setSelected(true);
            mViewPager.setCurrentItem(0);

            // tab2 Tab
            View tab2TabView = inflater.inflate(R.layout.tab, null);
            ImageView tab2TabIcon = (ImageView) tab2TabView.findViewById(R.id.tabIcon);
            tab2TabIcon.setImageResource(R.drawable.tab_second);
            TextView tab2TabText = (TextView) tab2TabView.findViewById(R.id.tabText);
            tab2TabText.setText("Odometer");
            tab2TabText.setTypeface(arialTypeface);
            tab2TabBadge = (TextView) tab2TabView.findViewById(R.id.tabBadge);
            tab2TabBadge.setTypeface(arialTypeface);
            tabLayout.getTabAt(1).setCustomView(tab2TabView);

            // tab3 Tab
            View tab3TabView = inflater.inflate(R.layout.tab, null);
            ImageView tab3TabIcon = (ImageView) tab3TabView.findViewById(R.id.tabIcon);
            tab3TabIcon.setImageResource(R.drawable.tab_third);
            TextView tab3TabText = (TextView) tab3TabView.findViewById(R.id.tabText);
            tab3TabText.setText("tab3");
            tab3TabText.setTypeface(arialTypeface);
            tab3TabBadge = (TextView) tab3TabView.findViewById(R.id.tabBadge);
            tab3TabBadge.setTypeface(arialTypeface);
            tabLayout.getTabAt(2).setCustomView(tab3TabView);

            // tab4 Tab
            View tab4TabView = inflater.inflate(R.layout.tab, null);
            ImageView tab4TabIcon = (ImageView) tab4TabView.findViewById(R.id.tabIcon);
            tab4TabIcon.setImageResource(R.drawable.tab_fourth);
            TextView tab4TabText = (TextView) tab4TabView.findViewById(R.id.tabText);
            tab4TabText.setText("tab4");
            tab4TabText.setTypeface(arialTypeface);
            tab4TabBadge = (TextView) tab4TabView.findViewById(R.id.tabBadge);
            tab4TabBadge.setTypeface(arialTypeface);
            tabLayout.getTabAt(3).setCustomView(tab4TabView);

            // tab5 Tab
            View tab5TabView = inflater.inflate(R.layout.tab, null);
            ImageView tab5TabIcon = (ImageView) tab5TabView.findViewById(R.id.tabIcon);
            tab5TabIcon.setImageResource(R.drawable.tab_fifth);
            TextView tab5TabText = (TextView) tab5TabView.findViewById(R.id.tabText);
            tab5TabText.setText("tab5");
            tab5TabText.setTypeface(arialTypeface);
            tab5TabBadge = (TextView) tab5TabView.findViewById(R.id.tabBadge);
            tab5TabBadge.setTypeface(arialTypeface);
            tabLayout.getTabAt(4).setCustomView(tab5TabView);

            // Tab listener
            /*
            tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
                @Override
                public void onTabSelected(TabLayout.Tab tab) {
                    txtViewHeading.setText(tab.getText());
                }

                @Override
                public void onTabUnselected(TabLayout.Tab tab) {

                }

                @Override
                public void onTabReselected(TabLayout.Tab tab) {

                }
            });
            */

        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            int id = item.getItemId();
            if (id == android.R.id.home) {
                if(mViewPager.getCurrentItem()==0){
                    onBackPressed();
                }
                else{
                    mViewPager.setCurrentItem(mViewPager.getCurrentItem()-1);
                }
            }
            return super.onOptionsItemSelected(item);
        }

        @Override
        protected void onPause() {
            super.onPause();
            isVisible = false;
        }

        @Override
        protected void onResume() {
            super.onResume();
            isVisible = true;
        }

        @Override
        protected void onStop() {
            super.onStop();
            isVisible = false;
        }

        private boolean checkPlayServices() {
            GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
            int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
            if (resultCode != ConnectionResult.SUCCESS) {
                if (apiAvailability.isUserResolvableError(resultCode)) {
                    apiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST)
                            .show();
                } else {
                    ToastNotify("This device is not supported by Google Play Services.");
                    finish();
                }
                return false;
            }
            return true;
        }

        public void ToastNotify(final String notificationMessage) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(Main.this, notificationMessage, Toast.LENGTH_LONG).show();
                }
            });
        }

        private void registerWithNotificationHubs()
        {
            if (checkPlayServices()) {
                // Start IntentService to register this application with GCM.
                Intent intent = new Intent(this, RegistrationIntentService.class);
                startService(intent);
            }
        }

    }

...and here is the code for my FragmentStatePagerAdapter

TabGroupAdapter

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.util.Log;

import java.util.ArrayList;


public class TabGroupAdapter extends FragmentStatePagerAdapter {

    private static int fragmentSize = 5;
    private static ArrayList<String> fragmentTitles = new ArrayList<String>() {
        {
            add("tab1");
            add("tab2");
            add("tab3");
            add("tab4");
            add("tab5");
        }
    };

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

    @Override
    public Fragment getItem(int position) {
        Log.d("tag","POSITION: " + position);
        switch (position) {
            case 0:
            default:
                return new Tab1Fragment();
            case 1:
                return new Tab2Fragment();
            case 2:
                return new Tab3Fragment();
            case 3:
                return new Tab4Fragment();
            case 4:
                return new Tab5Fragment();
        }
    }

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

    @Override
    public CharSequence getPageTitle(int position) {
        return fragmentTitles.get(position);
    }


}

To sum it up, when my app loads, the first tab is empty. Just a blank screen. It is not my Tab1Fragment as it should be. Also when I click through my tabs, the position should show from left to right 0,1,2,3,4 as I have 5 tabs. It does not though. I have a Log.d statement in my getItem(position) method in which I am logging the current position to the console. When my app loads it shows Position:0, then Position:1 all on load, which is weird since it should only show position 0 since that is the default tab (tab1). Then when I click through, tab 2 shows position 2, tab 3 shows position 3, tab 4 shows position 4 and tab 5 does not log at all. Then working back from tab 5 to tab 1, the positions are all out of whack, and when I get to tab 1 it does not log. It's quite strange. Also, my back arrow in my fragment that SHOULD only show up if I am not at the root fragment of the tab, instead shows up all the time.

Can anyone please help me figure out why this is happening? If any more code is needed to determine the problem, I am happy to post it just please let me know what you need to see.

Gal answered 11/7, 2016 at 22:10 Comment(0)
T
1

Try commenting out all of the code beneath:

 TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
        tabLayout.setupWithViewPager(mViewPager);

in your onCreate method. Run again and see what happens.

Your switch statement is laid out in a strange way, too. If you'll definitely only have 5 cases, then it should go from case 0-4, with a default case at the end that prints an error to the log, or throws an exception. I don't think this will be causing your issue, but it's good practice.

Also it's usually not a good idea to instantiate fragments using the default constructor. A better way is to use a static factory method, ie:

Tab1Fragment fragment = Tab1Fragment.create();
return fragment;

With a static create() method in your fragment, that initialises the object. It gives you a single access point to fragment, and means that any initialisation you need to do (now or at some point down the line) can all be done in once place, making you less prone to error. Android also re-creates fragments using the default constructor, so any initialisation you come to do in an overloaded constructor will be ignored. Again I don't think this is the cause of your issue, but it's worth bearing in mind.

Edit: In addition, when you say it is choosing random fragments "The position will show 0,3,2,0,4,1 just random numbers", do you mean those are the fragments being displayed on screen, or are those the positions you're logging from the "getItem(int position)" argument?

Trochee answered 11/7, 2016 at 23:14 Comment(3)
thank you for your insight. I commented out the code below the lines you mentioned above, but still the same problem remains. When I meant on the random fragments position is the Log I call from the getItem method. I have a Log.d("Mytag","Position:" + position); from within the getItem method. When my app loads, it logs "Position:0", then Position:1 all on load. Then when i click tab 2, it says Position:2, tab 3 says position:3, tab 4 says Position:4 and tab 5 does not log at all. then when I work back from tab 5 to tab 1, the sequence is all out of whackGal
I built a dummy project out of the code you've posted here and everything is working as it should. A FragmentStatePager adapter will load the current page, and one page either side. That is why it logs 0 and 1 at the same time. When you switch to page 2, it will load page 3 and keep page 1 in memory. Then when you get to page 4 it will not load anything, as 4 was loaded when you scrolled to 3 and there is nothing beyond that. So the int that you're being given in getItem() is NOT the page that is currently being viewed, is the one being loaded into memory. Hope that clears things up for you.Trochee
Thank you Dan. Your comment helped me to realize that my problem was not with the position returned, but rather the problem is in the fragment that I am loading.Gal
W
0
viewPager = (ViewPager) findViewById(R.id.tabPager);
 adapter = new ViewPagerAdapter(getSupportFragmentManager());
        adapter.addFragment(new Fragment1(),"fragment 1");
        adapter.addFragment(new Fragment2(),"fragment 2");
        viewPager.setAdapter(adapter);


        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
               return position;
                }
            }

            @Override
            public void onPageSelected(int position) {

            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
 tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        assert tabLayout != null;
        tabLayout.setupWithViewPager(viewPager);
        tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
        tabLayout.setTabMode(TabLayout.MODE_FIXED);
        tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);

Then in your Adapter

class ViewPagerAdapter extends FragmentPagerAdapter {
 private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();

        public ViewPagerAdapter(FragmentManager manager) {
            super(manager);
        }

        @Override
        public Fragment getItem(int position) {
            return mFragmentList.get(position);
        }

        @Override
        public int getCount() {
            return mFragmentList.size();
        }

        public void addFragment(Fragment fragment,String title) {
            mFragmentList.add(fragment);
 mFragmentTitleList.add(title);

        }

        @Override
        public CharSequence getPageTitle(int position) {
            return mFragmentTitleList.get(position);
        }
    }
Williswillison answered 12/7, 2016 at 6:12 Comment(1)
your getPageTitle method is returning a Fragment instead of a CharSequenceGal

© 2022 - 2024 — McMap. All rights reserved.