Dividing data amongst 3 actionbar tabs - android

I have an activity that has 3 actionbar sherlock tabs. This activity has a long list of data that I want divided evenly amongst these 3 tabs. The reason is since this list is long, it's easier for the user to find what he needs if the list is divided alphabetically amongst 3 tabs.
Clicking any tab shows the same list, just populated with different values, so I just wanted 1 fragment, called ListFragment that extends SherlockFragment. In the ListFragment's onCreateView I want to create the adapter using the appropriate list via getActivity().getSecondList, etc.
How can this ListFragment know which tab was selected to grab the right list from it's containing activity?
public class SherlockTabListener<T extends SherlockFragment> implements TabListener {
private SherlockFragment mFragment;
private final SherlockFragmentActivity mActivity;
private final String mTag;
private final Class<T> mClass;
private final int mfragmentContainerId;
public SherlockTabListener(int fragmentContainerId, SherlockFragmentActivity activity,
String tag, Class<T> clz) {
mActivity = activity;
mTag = tag;
mClass = clz;
mfragmentContainerId = fragmentContainerId;
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if(mTag.equals("AH")) {
mFragment = ListFragment.newInstance(firstList);
}
else if(mTag.equals("IQ")) {
mFragment = ListFragment.newInstance(middleList);
}
else
mFragment = ListFragment.newInstance(lastList);
ft.add(mfragmentContainerId, mFragment, mTag);
}

Related

Main activity calling seperate activities for each tab in actionbar(support.v7)

i am using actionbar(support.v7) with 4 tabs using fragments. I want each tab to have a separate activity rather than a common activity calling fragments?
ApplicationMainTabsActivity
public class ApplicationMainTabsActivity extends ActionBarActivity {
ActionBar.Tab Tab1, Tab2, Tab3,Tab4;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
String label1 = getResources().getString(R.string.label1);
Tab1 = actionBar.newTab();
Tab1.setText(label1);
ApplicationTabListener<Fragment1> tl = new ApplicationTabListener<Fragment1>(this,label1, Fragment1.class);
Tab1.setTabListener(tl);
actionBar.addTab(Tab1);
String label2 = getResources().getString(R.string.label2);
Tab2 = actionBar.newTab();
Tab2.setText(label2);
ApplicationTabListener<Fragment2> t2 = new ApplicationTabListener<Fragment2>(this,label2, Fragment2.class);
Tab2.setTabListener(t2);
actionBar.addTab(Tab2);
String label3 = getResources().getString(R.string.label3);
Tab3 = actionBar.newTab();
Tab3.setText(label3);
ApplicationTabListener<Fragment3> t3 = new ApplicationTabListener<Fragment3>(this,label3, Fragment3.class);
Tab3.setTabListener(t3);
actionBar.addTab(Tab3);
String label4 = getResources().getString(R.string.label4);
Tab4 = actionBar.newTab();
Tab4.setText(label4);
ApplicationTabListener<Fragment4> t4 = new ApplicationTabListener<Fragment4>(this,label4, Fragment4.class);
Tab4.setTabListener(t4);
actionBar.addTab(Tab4);
}
ApplicationTabListener.java
final class ApplicationTabListener<T extends Activity> implements ActionBar.TabListener {
private Fragment mFragment;
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
private final Bundle mArgs;
/**
* Constructor used each time a new tab is created.
*
* #param activity
* The host Activity, used to instantiate the fragment
* #param tag
* The identifier tag for the fragment
* #param clz
* The fragment's Class, used to instantiate the fragment
*/
public ApplicationTabListener(Activity activity, String tag, Class<T> clz) {
this(activity, tag, clz, null);
}
public ApplicationTabListener(Activity activity, String tag, Class<T> clz, Bundle args) {
mActivity = activity;
mTag = tag;
mClass = clz;
mArgs = args;
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// Check if the fragment is already initialized
if (mFragment == null) {
// If not, instantiate and add it to the activity
mFragment = Fragment.instantiate(mActivity, mClass.getName());
ft.add(R.id.action_bar_activity_content, mFragment, mTag);
} else {
// If it exists, simply attach it in order to show it
ft.replace(R.id.action_bar_activity_content,mFragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
// Detach the fragment, because another one is being attached
ft.remove(mFragment);
}
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// User selected the already selected tab. Usually do nothing.
}
}
Fragment1.java
public class Fragment1 extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.main, container, false);
}
}
You cannot have separate activity for each Tab which was used to be as in TabActivity. And it's deprecated. You need to attach fragments in order to use it. Otherwise you need to build your own custom TabActivity.

Delay initialization when using Fragment in Android

When one fragment A is changed to another fragment B, it will call onCreate() and some other functions to do initialization. After the Fragment has changed, the fragments near the current fragment also will be initialized. For example: I have 5 fragments A, B, C, D, E. The current fragment is A. When I change to D, D along with C and E will be initialized. My Problem is:
Some codes are very slow to execute so I want to initialize a part of the data instead of ALL of the data. That is, when the fragment is visible, then some data will be initialized. When its not the current fragment, the initialization will be delayed. Here is a pic:
I use these classes:
android.widget.TabHost
android.support.v4.app.Fragment
android.support.v4.app.FragmentActivity
android.support.v4.app.FragmentPagerAdapter
android.support.v4.view.ViewPager
I read the API but there is no method called when the fragment is VISIBLE. So, I think I can do something with onTabChanged. But I don't know how to get the content fragment through TabHost. If I can, then I will call my own function to do initialization.
How can I know the fragment is hide or its the current one? OR
Can I get the content fragment in TabHost? OR
Other ways to delay the initialization.
Here is some code:
public 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>();
private static final class TabInfo {
private final Class<?> mClss;
private final Bundle mArgs;
TabInfo(String _tag, Class<?> _class, Bundle _args) {
mClss = _class;
mArgs = _args;
}
}
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);
}
/** MainActivity call this func to add tabs */
public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
some code
}
public void onPageSelected(int position) {
TabWidget widget = mTabHost.getTabWidget();
int oldFocusability = widget.getDescendantFocusability();
widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
mTabHost.setCurrentTab(position);
widget.setDescendantFocusability(oldFocusability);
Log.i("demo tab","onPageSelected tab change to--------- " + position);
}
}
MainActivity:
/** these code is to create fragment */
FrameLayout tabContact = (FrameLayout) LayoutInflater.from(this).inflate(R.layout.tab_widget, null);
ImageView imgBackContact = (ImageView) tabContact.findViewById(R.id.tab_widget_back_image);
ImageView imgFrontContact = (ImageView) tabContact.findViewById(R.id.tab_widget_front_image);
imgBackContact.setImageResource(R.drawable.ic_tab_contact_normal);
imgFrontContact.setImageResource(R.drawable.ic_tab_contact_selected);
/** these code is to put fragments into TabHost */
mTabsAdapter.addTab(mTabHost.newTabSpec(XXX), A.class, null);
My Problem Is: some codes are very slow so I want to initialize a part
of the datas instead of ALL of them.
I hope you're not doing heavy operations on the main UI thread.
How can I know the fragment is hide or its the current one? OR Can I
get the content fragment in TabHost? OR Other ways to delay the
initialization.
You could use a trick regarding the FragmentPagerAdapter. In your onPageSelected method you could find out which is the current Fragment and call an initialization method on it:
public void onPageSelected(int position) {
//...
Fragment item = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.theIdOfTheViewPager + ":" + position);
if (item != null && item.getView() != null) {
item.initializeStuffForThisFragment();// you need to cast it to your Fragment class
}
}

Implementing Tab Navigation using the ActionBar and a Viewpager

I have 3 tabs, of which the 1st one has actual data(a listview) and rest 2 are empty. I was just trying to implement tab navigation.
in Activity's onCreate i have:
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.pager);
setContentView(mViewPager);
actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
PagerAdapter adapter = new PagerAdapter((SlidingFragmentActivity) this,
mViewPager);
adapter.addTab(actionBar.newTab().setText("Tab-1"),
Fragment1.class, null);
adapter.addTab(actionBar.newTab().setText("Tab-2"),
Fragment2.class, null);
adapter.addTab(actionBar.newTab().setText("Tab-3"),
Fragment2.class, null);
and the PagerAdapter is:
public static class PagerAdapter 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 PagerAdapter(SlidingFragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getSupportActionBar();
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();
}
public int getCount() {
return mTabs.size();
}
public SherlockFragment getItem(int position) {
TabInfo info = mTabs.get(position);
return (SherlockFragment) Fragment.instantiate(mContext,
info.clss.getName(), info.args);
}
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
public void onPageScrollStateChanged(int state) {
}
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
mViewPager.setCurrentItem(tab.getPosition());
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
Here Fragment1 has a listview which gets data from a web server using an AsyncTask.
Fragment2 is just an empty fragment
public class Fragment2 extends SherlockFragment {
}
Problem:
when i select Tab-2, then Tab-3 and comeback to Tab-2, Fragment1's onCreateView is being called. Though the Tab-2 shows white screen, Fragment1's onCreateView is being called, i checked using logcat.
Didnt i implement PagerAdapter the right way?
There is nothing wrong with this behaviour.
The ViewPager tries to minimize the memory impact that the fragments have. If you use a FragmentPagerAdapter the view of your fragment can be destroyed once it leaves the screen.
Typically the ViewPager will hold the view to the left and the right of the current view in memory to enable fast tab switching.
If you have only say 5 Tabs and you want to have all the views of this tabs in memory you can modify the number of views that are kept with ViewPager.setOffscreenPageLimit. This method lets you specify how many views are kept for each side. If you have only 5 tabs you could set 4 as offScreenPageLimit to have each view kept in memory even if the user is at one of the outer tabs.
Keep in mind that the views are destroyed for a reason. This is a performance optimization and even if offScreenPageLimit of 10 may work on your device it can crash devices with fewer memory. Set the limit to an reasonable number and implement the onDestroyView and oncreateView methods of your fragments correct.

Move between different tabs without create all the times the view

I have a doubt about my program.
I have 3 tabs in the action bar (made with fragments), each one shows a different view. These views have a lot of information that they collect from a database to show charts. The problem is that the ammount of information is quite big for read it everytime I change from one tab to another.
The question:
Is there any way to create each view only once and then just move between them?
The Activity:
String label1 = "one day";
Tab tab = actionBar.newTab();
tab.setText(label1);
TabListener<Tab1Fragment> tl = new TabListener<Tab1Fragment>(this, label1, Tab1Fragment.class);
tab.setTabListener(tl);
actionBar.addTab(tab);
String label2 = "two days";
tab = actionBar.newTab();
tab.setText(label2);
TabListener<Tab2Fragment> tl2 = new TabListener<Tab2Fragment>(this, label2, Tab2Fragment.class);
tab.setTabListener(tl2);
actionBar.addTab(tab);
String label3 = "three days";
tab = actionBar.newTab();
tab.setText(label3);
TabListener<Tab3Fragment> tl3 = new TabListener<Tab3Fragment>(this, label3, Tab3Fragment.class);
tab.setTabListener(tl3);
actionBar.addTab(tab);
The tab listener class:
private class TabListener<T extends Fragment> implements ActionBar.TabListener{
private Fragment fragment;
private final Activity activity;
private final String tag;
private final Class<T> classT;
public TabListener(Activity activityTab, String tagTab, Class<T> classTab) {
activity = activityTab;
tag = tagTab;
classT = classTab;
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (fragment == null) {
fragment = Fragment.instantiate(activity, classT.getName());
ft.add(android.R.id.content, fragment, tag);
} else {
ft.attach(fragment); }
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.detach(fragment);
}
And one of the fragments (the 3 are the same, only change the R.layout.**):
public class Tab1Fragment extends Fragment {
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
setRetainInstance(true);
return (LinearLayout) inflater.inflate(R.layout.main, container, false);
Thank you!
Each fragment can retain its state. Call setRetainInstance(true) in the fragment constructor.
Then you should fetch the data only if it has not already been fetched (if your store you data in a List, set that list to null in the constructor, create and fill it when you fetch data, and in the onStart method, if the list is null, fetch the data. Else, do nothing).
See also: Persisting list items in ListAdapter on configurationChanges with setRetainInstance

android tabs with interactive views

I am trying to avoid using intents and activities within tabhost and tabwidget
This code is starting to get messy just using views for everything.
My problem is that I am having difficulty retaining information. In one tab I have one view which has 4 buttons, each button loads another view and this takes up the visual information on screen in that tab. The problem is that when I go "back" to load the previous view in that tab, none of the information is that view is retained, even the button listeners won't re-instantiate.
How do I approach this? I have seen some very rudimentary examples of views within tabs, but nothing interactive that loads more views.
(viewflippers and action bars are not an option, and I am trying to avoid using tabs with activities)
Forget Activity Group. Forget Tab Host. It's all about ActionBar Tabs and ViewPager Fragments now. The API Demos sample app (which is also the Android Compatibility Library sample app) provides an implementation that combines both Tab and ViewPager navigation between Fragments, but it sort of fakes the Tabs (i.e., they are not true ActionBar tabs). See FragmentTabsPager.java. You can take this and make it work with true ActionBar tabs, too.
Here's the interesting bit. (I deleted a bunch of stuff, so don't look for a complete working solution here.)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_tabs_pager);
mViewPager = (ViewPager)findViewById(R.id.pager);
// This block thanks to https://stackoverflow.com/q/9790279/517561
ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayShowTitleEnabled(true);
bar.setDisplayShowHomeEnabled(true);
//
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab("simple", "Simple",
FragmentStackSupport.CountingFragment.class, null);
mTabsAdapter.addTab("contacts", "Contacts",
LoaderCursorSupport.CursorLoaderListFragment.class, null);
mTabsAdapter.addTab("custom", "Custom",
LoaderCustomSupport.AppListFragment.class, null);
mTabsAdapter.addTab("throttle", "Throttle",
LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);
}
public static class TabsAdapter extends FragmentPagerAdapter
implements ViewPager.OnPageChangeListener, ActionBar.TabListener {
private final SherlockFragmentActivity mContext;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
#SuppressWarnings("unused")
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(SherlockFragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(String tag, CharSequence label, Class<?> clss, Bundle args) {
ActionBar.Tab tab = mContext.getSupportActionBar().newTab();
tab.setText(label);
tab.setTabListener(this);
mContext.getSupportActionBar().addTab(tab);
TabInfo info = new TabInfo(tag, clss, args);
mTabs.add(info);
notifyDataSetChanged();
}
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
#Override
public void onPageSelected(int position) {
mContext.getSupportActionBar().setSelectedNavigationItem(position);
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
mViewPager.setCurrentItem(mContext.getSupportActionBar().getSelectedNavigationIndex());
}
}
My complete solution: http://code.google.com/p/sherlock-demo/
Note: Requires ActionBarSherlock.
Note: Thanks to ActionBarSherlock and FragmentTabsPager
User Activity Group for tabs and put any beautiful layout you create for tab or activities.
Here we go: http://ericharlow.blogspot.com/2010/09/experience-multiple-android-activities.html

Categories

Resources