implementing tabs with simple views and fragments - android

After one week struggle with common ways of implementing tabs like TabActivity and fragments and viewPager I failed to get a instance of Activities or fragments of tabs and couldn't find a way to solve the issue. So I decided to implement it in a different way. First I make a tabWidget with a simple button. In android developer website I find out a way to replace fragment in runtime. so the only thing remains is that how to get access to tab fragments to invoke methods from my FragmentActivity.
here is my FragmentActivity using pageViewer. I get nullpointer when I want to get fragment object of my tab in setup() method:
public class MainActivity extends FragmentActivity implements
OnTabChangeListener, OnPageChangeListener {
private TabHost mTabHost;
private ViewPager mViewPager;
private HashMap<String, TabInfo> mapTabInfo = new HashMap<String, MainActivity.TabInfo>();
private PagerAdapter mPagerAdapter;
private TabInfo mLastTab = null;
private class TabInfo {
private String tag;
private Class clss;
private Bundle args;
private Fragment fragment;
TabInfo(String tag, Class clazz, Bundle args) {
this.tag = tag;
this.clss = clazz;
this.args = args;
}
}
class TabFactory implements TabContentFactory {
private final Context mContext;
/**
* #param context
*/
public TabFactory(Context context) {
mContext = context;
}
/**
* (non-Javadoc)
*
* #see android.widget.TabHost.TabContentFactory#createTabContent(java.lang.String)
*/
public View createTabContent(String tag) {
View v = new View(mContext);
v.setMinimumWidth(0);
v.setMinimumHeight(0);
return v;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
Log.d("checking", "setup tabs...");
setContentView(R.layout.activity_main);
// //
initialiseTabHost(savedInstanceState);
if (savedInstanceState != null) {
mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
}
intialiseViewPager();
// //
setup();
// ///
}
protected void onSaveInstanceState(Bundle outState) {
outState.putString("tab", mTabHost.getCurrentTabTag()); // save the tab
// selected
super.onSaveInstanceState(outState);
}
private void intialiseViewPager() {
List<Fragment> fragments = new Vector<Fragment>();
fragments
.add(Fragment.instantiate(this, CoachFragment.class.getName()));
fragments
.add(Fragment.instantiate(this, LogingFragment.class.getName()));
fragments.add(Fragment.instantiate(this,
HistoryFragment.class.getName()));
this.mPagerAdapter = new PagerAdapter(
super.getSupportFragmentManager(), fragments);
//
this.mViewPager = (ViewPager) super.findViewById(R.id.viewpager);
this.mViewPager.setAdapter(this.mPagerAdapter);
this.mViewPager.setOnPageChangeListener(this);
mViewPager.setOffscreenPageLimit(1000000);
}
private void initialiseTabHost(Bundle args) {
mTabHost = (TabHost) findViewById(android.R.id.tabhost);
mTabHost.setup();
mTabHost.getTabWidget().setDividerDrawable(R.drawable.tab_divider);
TabInfo tabInfo = null;
View tabView1 = createTabView(this, coach");
MainActivity.AddTab(this, this.mTabHost, this.mTabHost
.newTabSpec("Tab1").setIndicator(tabView1),
(tabInfo = new TabInfo("Tab1", CoachFragment.class, args)));
this.mapTabInfo.put(tabInfo.tag, tabInfo);
View tabView2 = createTabView(this, logbook");
MainActivity.AddTab(this, this.mTabHost, this.mTabHost
.newTabSpec("Tab2").setIndicator(tabView2),
(tabInfo = new TabInfo("Tab2", LogingFragment.class, args)));
this.mapTabInfo.put(tabInfo.tag, tabInfo);
View tabView3 = createTabView(this, "history");
MainActivity.AddTab(this, this.mTabHost, this.mTabHost
.newTabSpec("Tab3").setIndicator(tabView3),
(tabInfo = new TabInfo("Tab3", HistoryFragment.class, args)));
this.mapTabInfo.put(tabInfo.tag, tabInfo);
mTabHost.setOnTabChangedListener(this);
}
private static void AddTab(MainActivity activity, TabHost tabHost,
TabHost.TabSpec tabSpec, TabInfo tabInfo) {
// Attach a Tab view factory to the spec
tabSpec.setContent(activity.new TabFactory(activity));
tabHost.addTab(tabSpec);
}
public void setup() {
....
CoachFragment fragment=(CoachFragment) mPagerAdapter.getRegisteredFragment(mViewPager.getCurrentItem());
fragment.setTempView(R.id.welcome);
fragment.animate();
....
}
public void onTabChanged(String tag) {
// TabInfo newTab = this.mapTabInfo.get(tag);
int pos = this.mTabHost.getCurrentTab();
this.mViewPager.setCurrentItem(pos);
}
private static View createTabView(final Context context, final String text) {
View view = LayoutInflater.from(context)
.inflate(R.layout.tabs_bg, null);
TextView tv = (TextView) view.findViewById(R.id.tabsText);
tv.setText(text);
return view;
}
#Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
}
#Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
this.mTabHost.setCurrentTab(position);
}
}
my pageAdapter:
public class PagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
private HashMap<Integer, Fragment> registeredFragments=new HashMap<Integer, Fragment>();
/**
* #param fm
* #param fragments
*/
public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
/* (non-Javadoc)
* #see android.support.v4.app.FragmentPagerAdapter#getItem(int)
*/
#Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
/* (non-Javadoc)
* #see android.support.v4.view.PagerAdapter#getCount()
*/
#Override
public int getCount() {
return this.fragments.size();
}
}
and my LogingFragment. the other 2 fragments are exactly the same one:
public class LogingFragment extends Fragment{
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
// We have different layouts, and in one of them this
// fragment's containing frame doesn't exist. The fragment
// may still be created from its saved state, but there is
// no reason to try to create its view hierarchy because it
// won't be displayed. Note this is not needed -- we could
// just run the code below, where we would create and return
// the view hierarchy; it would just never be used.
return null;
}
return (LinearLayout)inflater.inflate(R.layout.coach_activity, container, false);
}
}
Every Thing works perfect and all looking and swiping works fine but in setup() method I get nullPointer. please help me with it.

I strongly recommend running and testing the sample Effective Navigation which uses Tabs and ViewPager
http://developer.android.com/training/implementing-navigation/index.html

Finally I figured it out what is the cause of nullpointer. pager adapter should be like this:
public class PagerAdapter extends FragmentPagerAdapter {
Fragment screens[];
public PagerAdapter(FragmentManager fm, MainActivity context) {
super(fm);
screens = new Fragment[3];
screens[0] = Fragment.instantiate(context,CoachFragment.class.getName() );
screens[1] = Fragment.instantiate(context,LogingFragment.class.getName() );
screens[2] = Fragment.instantiate(context,HistoryFragment.class.getName() );
}
#Override
public Fragment getItem(int index) {
if(index <= screens.length)
{
return screens[index];
}
return null;
}
#Override
public int getCount() {
return screens.length;
}
}
so instantiating view pager changes like below:
private void intialiseViewPager() {
this.mPagerAdapter = new PagerAdapter(super.getSupportFragmentManager(),this);
//
this.mViewPager = (ViewPager) super.findViewById(R.id.viewpager);
this.mViewPager.setAdapter(this.mPagerAdapter);
this.mViewPager.setOnPageChangeListener(this);
//
this.mViewPager = (ViewPager) super.findViewById(R.id.viewpager);
this.mViewPager.setAdapter(this.mPagerAdapter);
this.mViewPager.setOnPageChangeListener(this);
}
Thanks to #Bruno Mateus

It seems to me like you are new to android, so let me point you in the right direction (if you are not new to android, my apologies):
If you want to use tabs in your app, the newest and best way to do this is to use Action Bar tabs.
This only involves editing your menu.xml file and adding an onCreateOptionsMenu() method to your main activity.
Also, to answer your question,
so the only thing remains is that how to get access to tab fragments to invoke methods from my FragmentActivity
You shouldn't use your fragments to invoke methods from your fragment activity.
Again, I will point you in the right direction with this video, "Programming Android with fragments". It is a little long, but it will explain how to use fragments.
Use the video's example of fragments and combine it with example code from the action bar tabs page.
Best of luck
**Quick edit to clarify: You should use action bar tabs because that is the newest and easiest way of using tabs. It is the new 'best practice'. TabWidget and TabActivity are older, more complicated, and might even be deprecated for all I know.

Try GrilledUI library. It will do all the dirty work for you, even load tab list from XML.

Related

force ViewPager to call getItem when going up the backstack

I'm trying to create an Android application which contains a single activity with a container and a navigation drawer. The initialy empty container loads fragments which has a ViewPager inside a tab layout in which I load a frgment with a FragmentTransaction:
public static void replaceFragmentInContainer(FragmentManager fragmentManager, Fragment fragmentToShow,
boolean addToBackStack)
{
FragmentTransaction transaction = fragmentManager.beginTransaction();
if (addToBackStack)
{
transaction.addToBackStack(null);
}
transaction.replace(R.id.container, fragmentToShow);
transaction.commit();
}
The problem I'm facing is with the backstack. When a fragment is added to the backstack and I press the back button, the app does go back to the previous fragment like I want to and I do see the tabs layout itself, but the content of the tabs is empty like there was nothing loaded to that tab. When it happens, I manage to reload the tab's content only when choosing that screen again with the navigational drawer.
After debugging I saw that the pager adapter's getItem method is not getting called when pressing the back button. The adapter itself is FragmentStatePagerAdapter.
I tried overriding the getItemPosition method:
public int getItemPosition(Object object)
{
return POSITION_NONE;
}
but that method wasn't called either when pressing the back button so I end up seeing empty tabs.
And this is the tabs adapter which is also the ViewPager adapter:
public static class TabsAdapter extends FragmentStatePagerAdapter implements TabHost.OnTabChangeListener,
ViewPager.OnPageChangeListener
{
private final Context mContext;
private final TabHost mTabHost;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
public TabsAdapter(final FragmentActivity activity, final TabHost tabHost, final ViewPager pager)
{
super(activity.getSupportFragmentManager());
mContext = activity;
mTabHost = tabHost;
mViewPager = pager;
mTabHost.setOnTabChangedListener(this);
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public ViewPager getViewPager()
{
return mViewPager;
}
static final class TabInfo
{
private final String tag;
private final Class<?> clss;
private final Bundle args;
TabInfo(final String _tag, final Class<?> _class, final Bundle _args)
{
tag = _tag;
clss = _class;
args = _args;
}
}
static class TabFactory implements TabHost.TabContentFactory
{
private final Context mContext;
public TabFactory(final Context context)
{
mContext = context;
}
#Override
public View createTabContent(final String tag)
{
final View v = new View(mContext);
v.setMinimumWidth(0);
v.setMinimumHeight(0);
return v;
}
}
public void addTab(final TabHost.TabSpec tabSpec, final Class<?> clss, final Bundle args)
{
tabSpec.setContent(new TabFactory(mContext));
final String tag = tabSpec.getTag();
final TabInfo info = new TabInfo(tag, clss, args);
mTabs.add(info);
mTabHost.addTab(tabSpec);
notifyDataSetChanged();
}
#Override
public int getCount()
{
return mTabs.size();
}
#Override
public Fragment getItem(final int position)
{
final TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
// #Override
// public Object instantiateItem(ViewGroup container, int position)
// {
//
// // Inflate a new layout from the resources.
// View view = ((Activity) mContext).getLayoutInflater().inflate(
// R.layout.fragment_single_conversation, container, false);
// // Add the newly created View to the ViewPager
// container.addView(view);
//
// // Populate the GUI and views now
// return view;
// }
#Override
public int getItemPosition(Object object)
{
return POSITION_NONE;
}
#Override
public void onTabChanged(final String tabId)
{
final int position = mTabHost.getCurrentTab();
mViewPager.setCurrentItem(position);
}
#Override
public void onPageScrolled(final int position, final float positionOffset,
final int positionOffsetPixels)
{
}
#Override
public void onPageSelected(final int position)
{
// Unfortunately when TabHost changes the current tab, it kindly
// also takes care of putting focus on it when not in touch mode.
// The jerk.
// This hack tries to prevent this from pulling focus out of our
// ViewPager.
final TabWidget widget = mTabHost.getTabWidget();
final int oldFocusability = widget.getDescendantFocusability();
widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
mTabHost.setCurrentTab(position);
widget.setDescendantFocusability(oldFocusability);
}
#Override
public void onPageScrollStateChanged(final int state)
{
}
}
How can this issue be solved?

ViewPager and Fragments inconsistent behaviour compared to TabHost

I'm trying to implement a four tab ViewPager as TabHost does not support swiping. The issue here is that I have some Async calls in each of the fragments' OnCreateView and the calls from the next Fragment are made in addition to the one I slide to while using the ViewPager.
With TabHost however, this isn't the case. The calls from only the selected tab are made. Is it an issue with the ViewPager that I should be addressing or am I using the wrong callback method for Fragment?
Here's a partial code from the project:
public class MainActivity extends FragmentActivity implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {
private TabHost mTabHost;
private ViewPager mViewPager;
private HashMap<String, TabInfo> mapTabInfo = new HashMap<String, MainActivity.TabInfo>();
private PagerAdapter mPagerAdapter;
private class TabInfo {
private String tag;
private Class<?> clss;
private Bundle args;
private Fragment fragment;
TabInfo(String tag, Class<?> clazz, Bundle args) {
this.tag = tag;
this.clss = clazz;
this.args = args;
}
}
class TabFactory implements TabContentFactory {
private final Context mContext;
/**
* #param context
*/
public TabFactory(Context context) {
mContext = context;
}
public View createTabContent(String tag) {
View v = new View(mContext);
v.setMinimumWidth(0);
v.setMinimumHeight(0);
return v;
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate the layout
setContentView(R.layout.activity_main);
// Initialise the TabHost
this.initialiseTabHost(savedInstanceState);
if (savedInstanceState != null) {
mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
}
// Intialise ViewPager
this.intialiseViewPager();
}
protected void onSaveInstanceState(Bundle outState) {
outState.putString("tab", mTabHost.getCurrentTabTag()); //save the tab selected
super.onSaveInstanceState(outState);
}
private void intialiseViewPager() {
List<Fragment> fragments = new Vector<Fragment>();
fragments.add(new ActivityFeedFragment());
fragments.add(new InboxFragment());
fragments.add(new TaskFragment());
fragments.add(new CalendarEventFragment());
this.mPagerAdapter = new PagerAdapter(super.getSupportFragmentManager(), fragments);
this.mViewPager = (ViewPager)super.findViewById(R.id.viewpager);
this.mViewPager.setAdapter(this.mPagerAdapter);
this.mViewPager.setOnPageChangeListener(this);
}
private void initialiseTabHost(Bundle args) {
mTabHost = (TabHost)findViewById(android.R.id.tabhost);
mTabHost.setup();
TabInfo tabInfo = null;
MainActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab1").setIndicator("Tab 1"), ( tabInfo = new TabInfo("Tab1", ActivityFeedFragment.class, args)));
this.mapTabInfo.put(tabInfo.tag, tabInfo);
MainActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab2").setIndicator("Tab 2"), ( tabInfo = new TabInfo("Tab2", InboxFragment.class, args)));
this.mapTabInfo.put(tabInfo.tag, tabInfo);
MainActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab3").setIndicator("Tab 3"), ( tabInfo = new TabInfo("Tab3", TaskFragment.class, args)));
this.mapTabInfo.put(tabInfo.tag, tabInfo);
MainActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab4").setIndicator("Tab 4"), ( tabInfo = new TabInfo("Tab4", CalendarEventFragment.class, args)));
this.mapTabInfo.put(tabInfo.tag, tabInfo);
mTabHost.setOnTabChangedListener(this);
}
private static void AddTab(MainActivity activity, TabHost tabHost, TabHost.TabSpec tabSpec, TabInfo tabInfo) {
// Attach a Tab view factory to the spec
tabSpec.setContent(activity.new TabFactory(activity));
tabHost.addTab(tabSpec);
}
public void onTabChanged(String tag) {
int pos = this.mTabHost.getCurrentTab();
this.mViewPager.setCurrentItem(pos, true);
}
#Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
// TODO Auto-generated method stub
}
#Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
this.mTabHost.setCurrentTab(position);
}
#Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
}
}
Also, here is the adapter that I am using
public class PagerAdapter extends FragmentStatePagerAdapter {
private List<Fragment> fragments;
public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
#Override
public int getCount() {
return this.fragments.size();
}
}
If there is any suggestion regarding enabling swipe gestures in TabHost I am willing to try that as well.
By default ViewPager create and retain one page in addition to the current page, if you don't want that you can setOffscreenPageLimit of the ViewPager to 0
viewPager.setOffscreenPageLimit(0);
--
An alternative solution is to setOnPageChangeListener to the viewpager and fire the Async call when the fragment selected
private static class CustomOnPageChangeListener extends SimpleOnPageChangeListener
{
#Override
public void onPageSelected(int position)
{
switch(position){
case 1:
FirstFragment fragment1 = (FirstFragment) = FirstFragment.getInstance();
fragment1.startAsyncProcess();
break;
case 2:
SecondFragment fragment2 = (SecondFragment) = SecondFragment.getInstance();
fragment2.startAsyncProcess();
break;
}
super.onPageSelected(position);
}
}
...
viewPager.setOnPageChangeListener(new CustomOnPageChangeListener());
ViewPager loads the previous and next fragment in addition to the current fragment to provide smooth user experience. Therefore ur asynctasks from other fragments are getting called.
Wat i suggest u do is keep public static boolean variables in each fragment and in ur OnPageSelected method u can set these variables.
Then in ur onResume method of each method check if the value of this variable is true and then only execute ur asynctask.
If u do not prefer static variables then access ur fragments using fragment manager and set the values of booleans

String transfer from Activity to Fragment

I saw this code in the documentation of view pager. I want to pass a string from my activity to a fragment class. I figured I can pass it using the bundle args. How would I access it in my fragment class? Also can someone explain why we extend Fragment Activity here?
public class ActionBarTabsPager extends Activity {
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.pager);
setContentView(mViewPager);
final ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(bar.newTab().setText("Simple"),
CountingFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("List"),
FragmentPagerSupport.ArrayListFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Cursor"),
CursorFragment.class, null);
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}
/**
* This is a helper class that implements the management of tabs and all
* details of connecting a ViewPager with associated TabHost. It relies on a
* trick. Normally a tab host has a simple API for supplying a View or
* Intent that each tab will show. This is not sufficient for switching
* between pages. So instead we make the content part of the tab host
* 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
* view to show as the tab content. It listens to changes in tabs, and takes
* care of switch to the correct paged in the ViewPager whenever the selected
* tab changes.
*/
public static class TabsAdapter extends FragmentPagerAdapter
implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(Activity activity, ViewPager pager) {
super(activity.getFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
#Override
public int getCount() {
return mTabs.size();
}
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrollStateChanged(int state) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
}
We extend from FragmentActivity when we want to use Fragments for devices running on Android < 3.0. In order to use Fragments for android 2.3.3 or similar you need FragmentActivity which is in the Android support library.
Also you can access the bundle passed into the fragment in this way:-
private void LoadBundle()
{
Bundle b = getArguments();
if (b != null) {
int value=b.getInt("yourkey")
}
}
Call the LoadBundle() method anywhere in the fragment to load data passed into the fragment.
You can transfer data from Activity to Fragment like this:
FragmentA fragmentA = new FragmentA();
Bundle bundle = new Bundle();
bundle.putXXX("YourDataKey", YourDataValue);
fragmentA.setArguments(bundle);
getFragmentManager().beginTransaction().add(fragmentA);
In my opion , the reason why extends FragmentActivity is that it can then manage Fragment easily . The advatage of using Fragment is not that simple. please read the google android doc:
http://developer.android.com/guide/components/fragments.html

Weird issue refreshing ViewPager with new content:

I receive data from a web service that is parsed into an object in the Application class, this object which in my case is a Report class contains a list of Tabs that should populate the ViewPager. So this Report is stored in the currentReport parameter in the Application class.
Each tab should be a page in the ViewPager. So for the first time when I receive the data and parse it, all works perfectly and the View Pager is populated with the correct data and presents it.
My problem starts when I want to get a new Report from the server and refresh the ViewPager with the new data that was parsed into the currentReport parameter.
My ViewPager is swipe-able and has tabs navigation, So when I try to re-instantiate the ViewPager with the new Report I see the right amount of tabs added to the tabHost. for some reason the fragments of the new report overlaping the fragment of the previos one. So if the number of tabs in the new report is bigger the tabs in the previous report then I can see the tabs from the previous report in addition to part of the new ones (if for example in the first report I had one tab, and in the new one I have 3 then I see the one fragment from the previous and the last 2 from the next one).
I have started my development from this tutorial and added smoe code to it:
http://thepseudocoder.wordpress.com/2011/10/13/android-tabs-viewpager-swipe-able-tabs-ftw/
This is my Tab Activity code:
public class TabsViewPagerFragmentActivity extends FragmentActivity implements ViewPager.OnPageChangeListener, TabHost.OnTabChangeListener
{
static final String TAG = TabsViewPagerFragmentActivity.class.getSimpleName();
private TabHost mTabHost;
private ViewPager mViewPager;
private HashMap<String, TabInfo> mapTabInfo;
public ViewPagerAdapter mPagerAdapter;
private TextView tvReportName, tvTabTitle;
private Button bBackToParameters;
private Dialog progressDialog;
private SGRaportManagerAppObj application;
private int numberOfTabs = 0;
private Display display;
public static final int POPUP_MARGIN = 6;
LeftSideMenu leftSideMenu;
public void NotifyTabActivityViewPagerAdapter()
{
mPagerAdapter.notifyDataSetChanged();
}
public ViewPagerAdapter getTabActivityViewPagerAdapter()
{
return mPagerAdapter;
}
public ViewPager getTabActivityViewPager()
{
return mViewPager;
}
public void setCurrentTabTitle (String title)
{
tvTabTitle.setText(title);
Log.d(TAG, "set tab title from activity: "+title);
}
/**
* Maintains extrinsic info of a tab's construct
*/
private class TabInfo
{
private String tag;
private Class<?> clss;
private Bundle args;
private Fragment fragment;
TabInfo(String tag, Class<?> clazz, Bundle args)
{
this.tag = tag;
this.clss = clazz;
this.args = args;
}
}
/**
* A simple factory that returns dummy views to the Tabhost
*/
class TabFactory implements TabContentFactory {
private final Context mContext;
/**
* #param context
*/
public TabFactory(Context context) {
mContext = context;
}
/** (non-Javadoc)
* #see android.widget.TabHost.TabContentFactory#createTabContent(java.lang.String)
*/
public View createTabContent(String tag) {
View v = new View(mContext);
v.setMinimumWidth(0);
v.setMinimumHeight(0);
return v;
}
}
/** (non-Javadoc)
* #see android.support.v4.app.FragmentActivity#onCreate(android.os.Bundle)
*/
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
application = SGRaportManagerAppObj.getInstance();
display = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
// Inflate the layout
setContentView(R.layout.tabs_screen_activity_layout);
tvTabTitle = (TextView) findViewById(R.id.tvTabName);
tvReportName = (TextView)findViewById(R.id.tvReportName);
tvReportName.setText(application.currentReport.getName()+ " - ");
bBackToParameters = (Button) findViewById(R.id.bBackToParameters);
leftSideMenu = (LeftSideMenu) findViewById(R.id.leftSideMenu);
applyOnClickListenerToLeftSideMenu();
findViewById(R.id.showLeftMenuButton).setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
Display d = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int width = d.getWidth();
View panel = findViewById(R.id.leftSideMenu);
View appPanel = findViewById(R.id.appLayout);
if (panel.getVisibility() == View.GONE){
appPanel.setLayoutParams(new LinearLayout.LayoutParams(width, LayoutParams.FILL_PARENT));
panel.setVisibility(View.VISIBLE);
applyOnClickListenerToLeftSideMenu();
}else{
ToggleButton button = (ToggleButton) findViewById(R.id.showLeftMenuButton);
button.setChecked(false);
panel.setVisibility(View.GONE);
}
}
});
// Initialise the TabHost
progressDialog = DialogUtils.createProgressDialog(this, this.getString(R.string.populating_view_pager));
progressDialog.show();
if (SGRaportManagerAppObj.getInstance().parametersRepository.getParametersRepository().size() == 0)
{
bBackToParameters.setText(R.string.back_to_report_list);
}
this.initialiseTabHost(savedInstanceState);
if (savedInstanceState != null) {
mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); //set the tab as per the saved state
}
// Intialise ViewPager
this.intialiseViewPager();
progressDialog.dismiss();
}
/** (non-Javadoc)
* #see android.support.v4.app.FragmentActivity#onSaveInstanceState(android.os.Bundle)
*/
protected void onSaveInstanceState(Bundle outState) {
outState.putString("tab", mTabHost.getCurrentTabTag()); //save the tab selected
super.onSaveInstanceState(outState);
}
/**
* Initialise ViewPager
*/
public void intialiseViewPager()
{
List<Fragment> fragments = new Vector<Fragment>();
// TabInfo tabInfo = null;
if (application.getCurrentDataSource().equals(DataSource.SSRS))
{
numberOfTabs = application.currentReport.getTabsList().size();
}
else if (application.getCurrentDataSource().equals(DataSource.SGRDL))
{
numberOfTabs = application.currentReport.getODTabsList().size();
Log.d(TAG, "CURRENT REPORT FROM VIEW PAGER: "+ application.currentReport.toString());
}
Log.d(TAG,"Current Tabs number from TabsViewPager activity: " +numberOfTabs);
if (application.getCurrentDataSource().equals(DataSource.SSRS))
{
for (int i = 0; i < numberOfTabs; i++)
{
Tab tempTab = application.currentReport.getTabsList().get(i);
if (tempTab.getTabTemplateId() == 7)
{
GridFragment gridFragment = new GridFragment(tempTab);
fragments.add(gridFragment);
}
else if (tempTab.getTabTemplateId() == 8)
{
NewChartFragment chartFragment = new NewChartFragment(tempTab, this);
fragments.add(chartFragment);
}
}
}
else if (application.getCurrentDataSource().equals(DataSource.SGRDL))
{
for (int i = 0; i < numberOfTabs; i++)
{
ODTab tempTab = application.currentReport.getODTabsList().get(i);
if (tempTab.getTabType().equals(ODGrid.XML_GRID_ELEMENT))
{
GridFragment gridFragment = GridFragment.newInstance(tempTab.getTabId());
fragments.add(gridFragment);
}
else if (tempTab.getTabType().equals(ODChart.XML_CHART_ELEMENT))
{
NewChartFragment chartFragment = NewChartFragment.newInstance(tempTab.getTabId());
fragments.add(chartFragment);
}
}
}
Log.d(TAG, "Current report fragments set to adapter: "+fragments.toString());
/*
if (this.mPagerAdapter == null)
{
this.mPagerAdapter = new ViewPagerAdapter(super.getSupportFragmentManager(), fragments);
}
else
{
this.mPagerAdapter.removeAllFragments();
this.mPagerAdapter.addFragmentsListToAdapter(fragments);
}
*/
this.mPagerAdapter = new ViewPagerAdapter(super.getSupportFragmentManager(), fragments);
this.mViewPager = (ViewPager)super.findViewById(R.id.pager);
// this.mViewPager.setAdapter(null);
this.mViewPager.setAdapter(this.mPagerAdapter);
this.mViewPager.setOffscreenPageLimit(0);
this.mViewPager.setOnPageChangeListener(this);
Log.d(TAG, "Adapter initialized!");
}
/**
* Initialise the Tab Host
*/
public void initialiseTabHost(Bundle args) {
mTabHost = (TabHost)findViewById(android.R.id.tabhost);
/*
//new edit
if (mTabHost.getChildCount() > 0)
{
mTabHost.removeAllViews();
}
*/
mTabHost.setup();
TabInfo tabInfo = null;
mapTabInfo = new HashMap<String, TabsViewPagerFragmentActivity.TabInfo>();
if (args != null)
{}
else
{
if (application.getCurrentDataSource().equals(DataSource.SSRS))
{
int numberOfTabs = application.currentReport.getTabsList().size();
for (int i = 0; i < numberOfTabs; i++)
{
Tab tempTab = application.currentReport.getTabsList().get(i);
if (tempTab.getTabTemplateId() == 7)
{
//GridFragment gridFragment = new GridFragment(tempTab);
TabsViewPagerFragmentActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab "+String.valueOf(i)).setIndicator("Tab "+String.valueOf(i)), ( tabInfo = new TabInfo("Tab "+String.valueOf(i), GridFragment.class, args)));
this.mapTabInfo.put(tabInfo.tag, tabInfo);
}
else if (tempTab.getTabTemplateId() == 8)
{
TabsViewPagerFragmentActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab "+String.valueOf(i)).setIndicator("Tab "+String.valueOf(i)), ( tabInfo = new TabInfo("Tab "+String.valueOf(i), NewChartFragment.class, args)));
this.mapTabInfo.put(tabInfo.tag, tabInfo);
}
}
}
else if (application.getCurrentDataSource().equals(DataSource.SGRDL))
{
int numberOfTabs = application.currentReport.getODTabsList().size();
for (int i = 0; i < numberOfTabs; i++)
{
ODTab tempTab = application.currentReport.getODTabsList().get(i);
// Log.d(TAG,"Crashed Tab type: "+ tempTab.getTabType());
if (tempTab.getTabType().equals(ODGrid.XML_GRID_ELEMENT))
{
//GridFragment gridFragment = new GridFragment(tempTab);
TabsViewPagerFragmentActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab "+String.valueOf(i)).setIndicator("Tab "+String.valueOf(i)), ( tabInfo = new TabInfo("Tab "+String.valueOf(i), GridFragment.class, args)));
this.mapTabInfo.put(tabInfo.tag, tabInfo);
}
else if (tempTab.getTabType().equals(ODChart.XML_CHART_ELEMENT))
{
TabsViewPagerFragmentActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab "+String.valueOf(i)).setIndicator("Tab "+String.valueOf(i)), ( tabInfo = new TabInfo("Tab "+String.valueOf(i), NewChartFragment.class, args)));
this.mapTabInfo.put(tabInfo.tag, tabInfo);
}
}
}
}
// Default to first tab
//this.onTabChanged("Tab1");
//
mTabHost.setOnTabChangedListener(this);
}
/**
* Add Tab content to the Tabhost
* #param activity
* #param tabHost
* #param tabSpec
* #param clss
* #param args
*/
private static void AddTab(TabsViewPagerFragmentActivity activity, TabHost tabHost, TabHost.TabSpec tabSpec, TabInfo tabInfo)
{
// Attach a Tab view factory to the spec
ImageView indicator = new ImageView(activity.getBaseContext());
indicator.setPadding(10, 10, 10, 10);
indicator.setImageResource(R.drawable.tab_select_icon_selector);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(10, 10, 10, 10);
indicator.setLayoutParams(lp);
tabSpec.setIndicator(indicator);
tabSpec.setContent(activity.new TabFactory(activity));
tabHost.addTab(tabSpec);
}
/** (non-Javadoc)
* #see android.widget.TabHost.OnTabChangeListener#onTabChanged(java.lang.String)
*/
public void onTabChanged(String tag) {
//TabInfo newTab = this.mapTabInfo.get(tag);
int pos = this.mTabHost.getCurrentTab();
this.mViewPager.setCurrentItem(pos);
}
/* (non-Javadoc)
* #see android.support.v4.view.ViewPager.OnPageChangeListener#onPageScrolled(int, float, int)
*/
#Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* #see android.support.v4.view.ViewPager.OnPageChangeListener#onPageSelected(int)
*/
#Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
this.mTabHost.setCurrentTab(position);
}
/* (non-Javadoc)
* #see android.support.v4.view.ViewPager.OnPageChangeListener#onPageScrollStateChanged(int)
*/
#Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
}
and this is my Adapter code:
public class ViewPagerAdapter extends FragmentPagerAdapter
{
private List<Fragment> fragments;
/**
* #param fm
* #param fragments
*/
public ViewPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
/* (non-Javadoc)
* #see android.support.v4.app.FragmentPagerAdapter#getItem(int)
*/
#Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
/* (non-Javadoc)
* #see android.support.v4.view.PagerAdapter#getCount()
*/
#Override
public int getCount() {
return this.fragments.size();
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
My AsyncTask that parses the data and updated the ViewPager:
public class ParseSGRDLReportDataAsyncTask extends AsyncTask<String, Object, Report>{
static final String TAG = ParseSGRDLReportDataAsyncTask.class.getSimpleName();
private Activity activity;
private Exception exception;
private ResponseHandler responseHandler = new ResponseHandler();
private SGRaportManagerAppObj application;
private Dialog progressDialog;
public ParseSGRDLReportDataAsyncTask(LoginScrActivity activity) {
super();
this.activity = activity;
}
public ParseSGRDLReportDataAsyncTask(Activity currentActivity) {
super();
this.activity = currentActivity;
}
public void onPreExecute() {
application = SGRaportManagerAppObj.getInstance();
progressDialog = DialogUtils.createProgressDialog(activity, activity.getString(R.string.parse_data_dialog_message));
progressDialog.show();
}
#Override
protected Report doInBackground(String... params) {
String ReportDataString = params[0];
try{
return DataAccessManager.parseSGRDLReportData(ReportDataString);
}
catch (Exception e) {
exception = e;
return null;
}
}
#Override
public void onPostExecute(Report result) {
progressDialog.dismiss();
if (exception == null)
{
if (activity.getClass() == TabsViewPagerFragmentActivity.class)
{
application.currentReport = result;
Log.d(TAG, "Current report parsed is: "+result);
((TabsViewPagerFragmentActivity)activity).intialiseViewPager();
((TabsViewPagerFragmentActivity)activity).initialiseTabHost(null);
((TabsViewPagerFragmentActivity)activity).NotifyTabActivityViewPagerAdapter();
}
else
{
responseHandler.handleProcessSGRDLReportDataResult(result, activity);
}
}
else {
processException();
}
}
private void processException() {
Toast.makeText(activity, activity.getString(R.string.error_when_parsing_data), 3000).show();
}
}
Answer:
Following #Luksprog advice for all people that stumble on the same problem this is the final result that works for me, in the AsyncTask I needed to added this:
if (activity.getClass() == TabsViewPagerFragmentActivity.class)
{
TabsViewPagerFragmentActivity tempActivity = ((TabsViewPagerFragmentActivity)activity);
application.currentReport = result;
Log.d(TAG, "Current report parsed is: "+result);
List<Fragment> frags = tempActivity.getTabActivityViewPagerAdapter().getFragments(); // getter method in your adapter
FragmentTransaction ft = tempActivity.getSupportFragmentManager().beginTransaction();
for (int i = 0; i < frags.size(); i++)
{
ft.remove(frags.get(i));
}
ft.commit();
tempActivity.intialiseViewPager();
tempActivity.getTabHost().getTabWidget().removeAllViews();
tempActivity.initialiseTabHost(null);
tempActivity.NotifyTabActivityViewPagerAdapter();
}
When the main two point are to remove the previous added fragments from the FragmentManager/SupportFragmentManager using a FragmentTransaction to show the correct set of fragments in the ViewPager and to remove all view from the TabWidget before adding new ones.
I'm not sure you solved this, if yes ignore my answer. The link provided by Neron T is important(more important the advices given there to not reference the fragments of the adapter outside).
When you set the adapter the second time with the new data you'll keep seeing the old fragments because of the way the FragmentPagerAdapter is implemented. When you set the adapter again the adapter will first run the destroyItem() method in which its fragment will be detached from the ViewPager. Next the adapter will run the instantiateItem() method. In this method a check will be performed against the FragmentManager to see if any of the previous fragments aren't still available. This check will find the old fragments(at least for the old positions, that's why you get new fragments for position which weren't in the previous situation, there weren't any fragment at that moment) because they are simply detached from the ViewPager(but still available in the FragmentManager through findFragmentByTag()). If a fragment isn't found in the FragmentManager only then the getItem() method will be called, retrieving a fragment from your list.
You should revise your code to remove the list reference to those fragments, there are other ways to retrieve the fragments from the ViewPager(not quite ideal either). As a quick fix, you could try to manually remove the old fragments from the FragmentManager(just before setting the new adapter) to force the ViewPager.instantiateItem() method to always call getItem():
if (activity.getClass() == TabsViewPagerFragmentActivity.class) {
application.currentReport = result;
Log.d(TAG, "Current report parsed is: "+result);
ListFragment<Fragment> frags = ((ViewPagerAdapter)mViewPager.getAdapter()).getFragments(); // getter method in your adapter
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
for (int i = 0; i < mOldTmp.size(); i++) {
ft.remove(frags.get(i));
}
ft.commit();
((TabsViewPagerFragmentActivity)activity).intialiseViewPager();
((TabsViewPagerFragmentActivity)activity).initialiseTabHost(null);
((TabsViewPagerFragmentActivity)activity).NotifyTabActivityViewPagerAdapter();
}
This is not tested so try it and see if it works.
There are 2 solutions for this issue:
Solution 1 - the easy one
See here: https://stackoverflow.com/a/13467232/444324
Basically you need to add this code to your viewpager adapter:
#Override
public int getItemPosition(Object object){
return PagerAdapter.POSITION_NONE;
}
Solution 2 - the recommended one is well explained here: https://stackoverflow.com/a/8024557/444324
I am going to post some of my code so that you will get some idea.
adapter initialization and set it to the view-pager.
vfPageContainer = (ViewPager)findViewById(R.id.vfPageContainer);
mAdapter = new TestFragmentAdapter(this,getSupportFragmentManager());
vfPageContainer.setAdapter(mAdapter);
each time new data comes and i call below method:
updateUi() method
private void updateUi()
{
for(int i=0 ; i < alDataPages.size() ; i++)
{
mAdapter.addFragment(TestFragment.newInstance(this));
}
mAdapter.notifyDataSetChanged();
}
In TestFragmentAdapter class there r methods for add and clear the fragments from view-pager.
TestFragmentAdapter class
class TestFragmentAdapter extends FragmentStatePagerAdapter {
private Context context;
private ArrayList<Fragment> views = new ArrayList<Fragment>();
public TestFragmentAdapter(Context context,FragmentManager fm)
{
super(fm);
this.context = context;
views = new ArrayList<Fragment>();
}
#Override
public Fragment getItem(int position)
{
return views.get(position);
}
public void addFragment (Fragment v)
{
views.add(v);
}
public void clear()
{
for(int i = 0 ; i < views.size() ; i++)
{
views.clear();
}
}
#Override
public int getCount()
{
return views.size();
}
}
TestFragment class
public final static class TestFragment extends Fragment {
private Context context;
public void setContext(Context c)
{
context = c;
}
public static TestFragment newInstance(Context context)
{
TestFragment f = new TestFragment();
f.setContext(context);
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
WebView webView_viewpage = new WebView(context);
return webView_viewpage;
}
}
so when new data comes before that i call the below code. I am removing all the views from adapter and create new 1 and set it to the view-pager every time.You should also try this in you code it should work.
mAdapter.clear(); // previously it was not working so i created new adapter and set it to the viewpager.
mAdapter = new TestFragmentAdapter(this,getSupportFragmentManager());
vfPageContainer.setAdapter(mAdapter);
hope this help to you and you will find solution.

Android Viewpager Tabs updating tab fragment

I have an Activity which scrapes a webpage in a CustomLoader.
When loader finished I want to update the contents of 3 tabs with the data retrieved.
I'm using the sample code provided by android dev samples to implement the Viewpager/Tabs/Fragments on the activity.
When the fragment is created for the tab the onCreateView is correctly called, all the widgets on the view are correctly located and mapped to the variables.
However, when I attempt to find the fragment from the Activity and call a method on the fragment to update its contents the variables are null. Furthermore, calling getView also returns null - The instance of the fragment I'm retrieving from the TabsAdapter is not the correct instantiated instance ?
I've cut the code down to a single tab fragment, code in question is the call from onLoaderFinished to update the fragment.
All 3 tab fragments will be populated with data from a single loader, hence the loader being on the activity, not on the fragments. I just need a way to tell the fragments to paint their new data.
public class InfoBloodStocksActivity extends SherlockFragmentActivity
implements LoaderManager.LoaderCallbacks<BloodStocksLoaderResponse> {
TabHost mTabHost;
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.info_bloodstocks_tabpager);
mTabHost = (TabHost)findViewById(android.R.id.tabhost);
mTabHost.setup();
mViewPager = (ViewPager)findViewById(R.id.infoBloodStocksTabPager);
mViewPager.setOffscreenPageLimit(3);
mTabsAdapter = new TabsAdapter(this, mTabHost, mViewPager);
mTabsAdapter.addTab(mTabHost.newTabSpec("Daily stock").setIndicator("Daily stocks"),
InfoBloodStocksPageFragment.class, null);
if (savedInstanceState != null) {
mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
}
loadStockDetailsFromWebsite();
}
private void loadStockDetailsFromWebsite() {
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getSupportLoaderManager().initLoader(0, null, this);
}
#Override
public Loader<BloodStocksLoaderResponse> onCreateLoader(int arg0, Bundle arg1) {
// This is called when a new Loader needs to be created. This
// sample only has one Loader with no arguments, so it is simple.
return new BloodStocksCustomLoader(this);
}
#Override
public void onLoadFinished(Loader<BloodStocksLoaderResponse> loader, BloodStocksLoaderResponse response) {
if (response.isNewStocksLoaded()) {
InfoBloodStocksPageFragment fragment = (InfoBloodStocksPageFragment) mTabsAdapter.getItem(0);
fragment.setNewImage(response.getDailyStocksImageURL());
}
}
#Override
public void onLoaderReset(Loader<BloodStocksLoaderResponse> arg0) {
// TODO Auto-generated method stub
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("tab", mTabHost.getCurrentTabTag());
}
/**
* This is a helper class that implements the management of tabs and all
* details of connecting a ViewPager with associated TabHost. It relies on a
* trick. Normally a tab host has a simple API for supplying a View or
* Intent that each tab will show. This is not sufficient for switching
* between pages. So instead we make the content part of the tab host
* 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
* view to show as the tab content. It listens to changes in tabs, and takes
* care of switch to the correct paged in the ViewPager whenever the selected
* tab changes.
*/
public static class TabsAdapter extends FragmentPagerAdapter
implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final TabHost mTabHost;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final String tag;
private final Class<?> clss;
private final Bundle args;
TabInfo(String _tag, Class<?> _class, Bundle _args) {
tag = _tag;
clss = _class;
args = _args;
}
}
static class DummyTabFactory implements TabHost.TabContentFactory {
private final Context mContext;
public DummyTabFactory(Context context) {
mContext = context;
}
#Override
public View createTabContent(String tag) {
View v = new View(mContext);
v.setMinimumWidth(0);
v.setMinimumHeight(0);
return v;
}
}
public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mTabHost = tabHost;
mViewPager = pager;
mTabHost.setOnTabChangedListener(this);
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
tabSpec.setContent(new DummyTabFactory(mContext));
String tag = tabSpec.getTag();
TabInfo info = new TabInfo(tag, clss, args);
mTabs.add(info);
mTabHost.addTab(tabSpec);
notifyDataSetChanged();
}
#Override
public int getCount() {
return mTabs.size();
}
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
#Override
public void onTabChanged(String tabId) {
int position = mTabHost.getCurrentTab();
mViewPager.setCurrentItem(position);
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
// Unfortunately when TabHost changes the current tab, it kindly
// also takes care of putting focus on it when not in touch mode.
// The jerk.
// This hack tries to prevent this from pulling focus out of our
// ViewPager.
TabWidget widget = mTabHost.getTabWidget();
int oldFocusability = widget.getDescendantFocusability();
widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
mTabHost.setCurrentTab(position);
widget.setDescendantFocusability(oldFocusability);
}
#Override
public void onPageScrollStateChanged(int state) {
}
}
}
I'm calling setNewImage from the activity.
public class InfoBloodStocksPageFragment extends SherlockFragment {
private ImageView mImageView;
private ProgressBar mProgress;
private TextView mTitle;
private TextView mDescriptionText;
private String mImageURL;
private ImageLoader mImageLoader = ImageLoader.getInstance();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.info_bloodstocks_page, container, false);
mImageView = (ImageView)view.findViewById(R.id.bloodStocksPageImage);
mProgress = (ProgressBar)view.findViewById(R.id.bloodStocksPageProgress);
mTitle = (TextView)view.findViewById(R.id.bloodStockPageTitle);
mDescriptionText = (TextView)view.findViewById(R.id.bloodStocksPageText);
mProgress.setVisibility(View.VISIBLE);
mDescriptionText.setVisibility(View.GONE);
return view;
}
public void setNewImage(String imageURL) {
// why is mImageView null here ?
// why does getView() return null here ?
View view = getView();
mImageView = (ImageView)view.findViewById(R.id.bloodStocksPageImage);
DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder()
.showImageForEmptyUri(R.drawable.loading_stock_figures)
.cacheOnDisc()
.imageScaleType(ImageScaleType.EXACT)
.build();
mImageLoader.displayImage(imageURL, mImageView, displayImageOptions, new ImageLoadingListener() {
#Override
public void onLoadingStarted() {
mProgress.setVisibility(View.VISIBLE);
}
#Override
public void onLoadingFailed(FailReason failReason) {
String message = null;
switch (failReason) {
case IO_ERROR:
message = "Input/Output error";
break;
case OUT_OF_MEMORY:
message = "Out Of Memory error";
break;
case UNKNOWN:
message = "Unknown error";
break;
}
mProgress.setVisibility(View.GONE);
mImageView.setImageResource(android.R.drawable.ic_delete);
}
#Override
public void onLoadingComplete() {
mProgress.setVisibility(View.GONE);
Animation anim = AnimationUtils.loadAnimation(getActivity(), R.anim.fade_in);
mImageView.setAnimation(anim);
anim.start();
}
#Override
public void onLoadingCancelled() {
// Do nothing
}
});
}
}
I've just started using http://square.github.com/otto/ for doing this. The documentation on the site should be enough to get you started with it.

Categories

Resources