I am working on an Android application that uses ActionBarSherlock and ViewPagerIndicator. The main action is the SherlockFragmentActivity function, and users move between fragments through tabs in the action bar. All tabs are SherlockListFragments, and most of them contain only ListViews. However, one fragment (HeadlinesFragment) contains a ViewPager, CirclePageIndicator and ListView for tablets and only ListView on phones. ViewPager has a FragmentStatePagerAdapter that returns a Sherlock element for elements.
The problem is that when you change the orientation (or any configuration change), the child fragments inside the ViewPager do not reload, and the CirclePagerIndicator does not show any pointers, as if the ViewPager was empty. However, the ListView does reboot. When loading a fragment, ViewPager works correctly, but not after changing orientation.
MainActivity.java
public class MainActivity extends SherlockFragmentActivity {
private HashMap<Integer, String> tabData;
private HashMap<Integer, String> tabExtra;
private Fragment currentFragment = null;
private Fragment savedFragment = null;
public ActionBar mActionBar;
public MenuItem mRefresh;
public static int mCurrentPos;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
HashMap<String, Object> savedData = (HashMap<String, Object>) getLastCustomNonConfigurationInstance();
if (savedData != null) {
tabData = (HashMap<Integer, String>) savedData.get("tabData");
tabExtra = (HashMap<Integer, String>) savedData.get("tabExtra");
savedFragment = (Fragment) savedData.get("currentFragment");
mCurrentPos = ((Integer) savedData.get("pos")).intValue();
} else {
tabData = (HashMap<Integer, String>) getIntent().getExtras().getSerializable("tabData");
tabExtra = (HashMap<Integer, String>) getIntent().getExtras().getSerializable("tabExtra");
mCurrentPos = 0;
}
mActionBar = getSupportActionBar();
Const.IsTablet = Utils.isTablet(MainActivity.this);
TypedArray tabs = getResources().obtainTypedArray(R.array.TabBars);
Tab tab;
for (int i = 0; i < tabs.length(); i++) {
String tabInfo[] = getResources().getStringArray(tabs.getResourceId(i, 0));
tab = mActionBar.newTab().setText(tabInfo[1]);
if (tabInfo[0].equalsIgnoreCase("customizedNewsPage")) {
tab.setTabListener(new MainTabListener<HeadlinesFragment>(MainActivity.this, i, HeadlinesFragment.class));
}
mActionBar.addTab(tab);
}
tabs.recycle();
mActionBar.selectTab(mActionBar.getTabAt(mCurrentPos));
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
mActionBar.setBackgroundDrawable(getResources().getDrawable(R.drawable.navbar));
}
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message message) {
Bundle bundle = message.getData();
if (bundle.getInt("result") == Activity.RESULT_OK && bundle.getString("data") != null) {
tabData.put(Integer.valueOf(bundle.getInt("tabPos")), bundle.getString("data"));
DataType type = DataType.values()[bundle.getInt("type")];
switch (type) {
case Headlines:
((HeadlinesFragment) currentFragment).setData(bundle.getString("data"));
break;
}
tabData.put(Integer.valueOf(bundle.getInt("tabPos")), bundle.getString("data"));
setRefreshActionButtonState(false);
}
}
};
public Handler getHandler() {
return mHandler;
}
@Override
public Object onRetainCustomNonConfigurationInstance() {
final HashMap<String, Object> savedData = new HashMap<String, Object>();
savedData.put("currentFragment", currentFragment);
savedData.put("tabData", tabData);
savedData.put("tabExtra", tabExtra);
savedData.put("pos", Integer.valueOf(mCurrentPos));
return savedData;
}
private class MainTabListener<T extends Fragment> implements TabListener {
private Fragment mFragment;
private final SherlockFragmentActivity mActivity;
private final int mPos;
private final Class<T> mClass;
public MainTabListener(SherlockFragmentActivity activity, int pos, Class<T> clz) {
mActivity = activity;
mPos = pos;
mClass = clz;
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction ignoredFt) {
FragmentManager fragMgr = ((FragmentActivity) mActivity).getSupportFragmentManager();
FragmentTransaction ft = fragMgr.beginTransaction();
if (mFragment == null) {
mFragment = Fragment.instantiate(mActivity, mClass.getName());
Bundle args = new Bundle();
args.putString("data", tabData.get(mPos));
args.putInt("pos", mPos);
mFragment.setArguments(args);
ft.add(android.R.id.content, mFragment);
} else {
ft.attach(mFragment);
}
currentFragment = mFragment;
mCurrentPos = mPos;
mRefresh = null;
ft.commit();
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ignoredFt) {
FragmentManager fragMgr = ((FragmentActivity) mActivity).getSupportFragmentManager();
FragmentTransaction ft = fragMgr.beginTransaction();
fragMgr.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
if (mFragment == null) {
mFragment = SherlockFragment.instantiate(mActivity, mClass.getName());
ft.add(android.R.id.content, mFragment);
} else {
ft.detach(mFragment);
}
currentFragment = null;
ft.commit();
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ignoredFt) {
onTabUnselected(tab, ignoredFt);
onTabSelected(tab, ignoredFt);
}
}
}
HeadlinesFragment.java
public class HeadlinesFragment extends SherlockListFragment implements SearchView.OnQueryTextListener, SearchView.SearchViewChangeMode, OnItemClickListener {
private static final String LOG_TAG = "Headlines Fragment";
private JSONArray mHeadlines = new JSONArray();
private JSONArray mHeadlinesTop = new JSONArray();
private SearchView mSearchView;
private MenuItem mSearchItem;
private ViewPager mPager;
private CirclePageIndicator mIndicator;
private static int mPos;
private int mRotatorImageWidth;
private static HeadlinesFragment instance;
private Tracker tracker;
private Timer refreshTimer;
private int refreshTime = 0;;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
instance = this;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mPos = getArguments().getInt("pos");
TypedArray tabs = getResources().obtainTypedArray(R.array.TabBars);
String tabInfo[] = getResources().getStringArray(tabs.getResourceId(mPos, 0));
mRotatorImageWidth = Integer.valueOf(tabInfo[7]).intValue();
refreshTime = Integer.valueOf(tabInfo[4]).intValue();
tabs.recycle();
try {
mHeadlines = new JSONArray(getArguments().getString("data"));
} catch (NotFoundException e) {
Log.e(LOG_TAG, "Error loading data", e);
} catch (JSONException e) {
Log.e(LOG_TAG, "Error loading data", e);
}
return inflater.inflate(R.layout.activity_headlines, container, false);
}
@SuppressWarnings("deprecation")
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (((SIDHelpApplication) getActivity().getApplicationContext()).isTablet()) {
try {
mHeadlinesTop = new JSONArray();
JSONArray temp = new JSONArray();
for (int i = 0; i < mHeadlines.length(); i++) {
if (i < 5) {
mHeadlinesTop.put(mHeadlines.get(i));
} else {
temp.put(mHeadlines.get(i));
}
}
mHeadlines = temp;
} catch (JSONException e) {
Log.e(LOG_TAG, "Error splitting off top 5", e);
}
mPager = (ViewPager) getActivity().findViewById(R.id.rotator);
mPager.setOffscreenPageLimit(4);
mPager.setAdapter(new RotatorAdapter(this, getActivity(), mHeadlinesTop, mRotatorImageWidth, mPos));
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
mPager.getLayoutParams().height = (int) Math.floor((((float) getResources().getInteger(R.integer.NewsImageHeight) / (float) getResources().getInteger(R.integer.NewsImageWidth)) * (float) getActivity().getWindowManager().getDefaultDisplay().getWidth()));
}
mIndicator = (CirclePageIndicator) getActivity().findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
}
setListAdapter(new HeadlinesAdapter(getSherlockActivity(), mHeadlines));
getListView().setOnItemClickListener(this);
getListView().setEmptyView(getActivity().findViewById(android.R.id.empty));
setAutoRefresh();
}
public void setData(String data) {
setData(data, false);
}
public void setData(String data, boolean search) {
try {
mHeadlines = new JSONArray(data);
if (((SIDHelpApplication) getActivity().getApplicationContext()).isTablet() && !search) {
mHeadlinesTop = new JSONArray();
try {
JSONArray temp = new JSONArray();
for (int i = 0; i < mHeadlines.length(); i++) {
if (i < 5) {
mHeadlinesTop.put(mHeadlines.get(i));
} else {
temp.put(mHeadlines.get(i));
}
}
mHeadlines = temp;
} catch (JSONException e) {
Log.e(LOG_TAG, "Error splitting off top 5", e);
}
((RotatorAdapter) mPager.getAdapter()).setData(mHeadlinesTop);
mPager.setVisibility(View.VISIBLE);
mIndicator.setVisibility(View.VISIBLE);
} else {
getActivity().findViewById(android.R.id.empty).setVisibility(View.GONE);
}
if (search && mPager != null) {
mPager.setVisibility(View.GONE);
mIndicator.setVisibility(View.GONE);
}
((HeadlinesAdapter) getListAdapter()).setData(mHeadlines);
setAutoRefresh();
} catch (JSONException e) {
Log.e(LOG_TAG, "Setting Data", e);
}
}
public static HeadlinesFragment getInstance() {
return instance;
}
}
activity_headlines.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/llMainHeadline"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="false"
android:focusableInTouchMode="true"
android:background="@drawable/bg_img" >
<android.support.v4.view.ViewPager
android:id="@+id/rotator"
android:layout_width="match_parent"
android:layout_height="@dimen/headlines_rotator_height"
android:layout_alignParentTop="true"
android:background="@android:color/black" />
<com.viewpagerindicator.CirclePageIndicator
android:id="@+id/indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/rotator"
android:background="@android:color/black"
android:padding="10dp" />
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_below="@id/indicator"
android:cacheColorHint="#00000000"
android:listSelector="@color/TableCellSelection" />
<TextView
android:id="@android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/noResults"
android:textSize="@dimen/noResult_text_size"
android:textStyle="bold"
android:visibility="gone" />
</RelativeLayout>
RotatorAdapter.java
public class RotatorAdapter extends FragmentStatePagerAdapter {
private static final String LOG_TAG = "Rotator Adapter";
private Context mContext;
private JSONArray mData;
private int mImageWidth;
private int mPos;
public RotatorAdapter(SherlockListFragment fragment, Context context, JSONArray data, int imageWidth, int pos) {
super(fragment.getChildFragmentManager());
mContext = context;
mData = data;
mImageWidth = imageWidth;
mPos = pos;
}
@Override
public int getCount() {
return mData.length();
}
@Override
public Fragment getItem(int pos) {
Fragment fragment = null;
Bundle args = new Bundle();
try {
JSONObject hdata = mData.getJSONObject(pos);
args.putString("title", hdata.getString(mContext.getResources().getString(R.string.tag_title)));
args.putString("category", hdata.getString(mContext.getResources().getString(R.string.tag_category)));
args.putString("time", hdata.getString(mContext.getResources().getString(R.string.tag_time)));
args.putString("newsID", hdata.getString(mContext.getResources().getString(R.string.tag_newsID)));
args.putString("photoURL", hdata.getString(mContext.getResources().getString(R.string.tag_photoURL)));
args.putInt("imageWidth", mImageWidth);
args.putInt("pos", mPos);
fragment = Fragment.instantiate(mContext, RotatorFragment.class.getName(), args);
} catch (JSONException e) {
Log.e(LOG_TAG, "Error getting data", e);
}
return fragment;
}
public void setData(JSONArray data) {
mData = data;
notifyDataSetChanged();
}
}
RotatorFragment.java
public class RotatorFragment extends SherlockFragment implements OnClickListener {
private static final String LOG_TAG = "Rotator Fragment";
private String mNewsID;
private int mPos;
private ImageLoader imageLoader = ImageLoader.getInstance();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_headlines_top_row, container, false);
ImageView image = (ImageView) view.findViewById(R.id.imgArticle);
String photoURL = getArguments().getString("photoURL").replaceAll(" ", "%20");
imageLoader.displayImage(photoURL, image);
TextView headlineTitle = (TextView) view.findViewById(R.id.txtTitle);
TextView headlineCategory = (TextView) view.findViewById(R.id.txtCategory);
headlineTitle.setText(getArguments().getString("title"));
headlineCategory.setText(String.format("%s - %s", getArguments().getString("category"), getArguments().getString("time")));
mNewsID = getArguments().getString("newsID");
mPos = getArguments().getInt("pos");
view.setOnClickListener(this);
return view;
}
@Override
public void onClick(View v) {
Log.i(LOG_TAG, "Loading Article");
Intent dataIntent = new Intent(getActivity(), DataLoader.class);
Messenger dataMessenger = new Messenger(HeadlinesFragment.mHandler);
dataIntent.putExtra("MESSENGER", dataMessenger);
dataIntent.putExtra("tabPos", mPos);
dataIntent.putExtra("type", DataType.HeadlinesArticle.ordinal());
String params[] = new String[] {mNewsID};
dataIntent.putExtra("params", params);
getActivity().startService(dataIntent);
}
@Override
public void onSaveInstanceState (Bundle outState) {
}
}