Phil Phil - 4 months ago 70
Android Question

FragmentStatePagerAdapter - getItem

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.

Dan Dan
Answer

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?

Comments