In my onCreate() method I try to manually select one of my tabs to force it to pre-load, then switch back to the first tab manually. However, when I start, the first tab initally displays a blank screen and only loads after selecting another and then reselecting. This is my code in onCreate:
//set up tabs
actionBar.addTab(actionBar.newTab()
.setText("Set Current Location")
.setTabListener(new CustomTabListener<SetCurrentLocationFragment>(currLocFragment,this,SetCurrentLocationFragment.class)),true);
actionBar.addTab(actionBar.newTab()
.setText("Input Trip")
.setTabListener(new CustomTabListener<InputNewTripFragment>(inputNewTripFragment,this,InputNewTripFragment.class)));
actionBar.addTab(actionBar.newTab()
.setText("View Trip")
.setTabListener(new CustomTabListener<FoodMilesFragment>(calcMilesFragment,this,FoodMilesFragment.class)));
actionBar.addTab(actionBar.newTab()
.setText("Past Trips")
.setTabListener(new CustomTabListener<TripHistoryFragment>(tripHistoryFragment,this,TripHistoryFragment.class)));
actionBar.addTab(actionBar.newTab()
.setText("Trip Map")
.setTabListener(new CustomTabListener<ResultsMapFragment>(resultsMapFragment,this,ResultsMapFragment.class)));
//quickly pre-load the View Trip
actionBar.setSelectedNavigationItem(2);
actionBar.setSelectedNavigationItem(0);
And this is my TabListener
private class CustomTabListener<T extends Fragment> implements TabListener {
private Fragment fragment;
private final Activity mBaseActivity;//activity to attach fragment to
private final Class<T> mFragmentClass;
public CustomTabListener(Fragment fragment, Activity activity, Class<T> fragClass)
{
this.fragment = fragment;
mBaseActivity = activity;
mFragmentClass = fragClass;
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if(fragment == null)
{
throw new IllegalArgumentException("Fragment must already be instantiated.");
}
//if the fragment has not yet been added to the activity, add it now
if(fragment.getActivity() == null || !fragment.isAdded())
ft.add(R.id.tabFragmentFrame, fragment);
ft.show(fragment);
fragment.setUserVisibleHint(true);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if(fragment != null)
{
ft.remove(fragment);
fragment.setUserVisibleHint(false);
}
}
}
Something worth mentioning as well is that this version of my TabListener, with ft.hide(fragment) substituted for ft.remove(fragment) led to IllegalStateExceptions - Fragment already added.
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if(fragment == null)
{
throw new IllegalArgumentException("Fragment must already be instantiated.");
}
//if the fragment has not yet been added to the activity, add it now
if(fragment.getActivity() == null || !fragment.isAdded())
ft.add(R.id.tabFragmentFrame, fragment);
ft.show(fragment);
fragment.setUserVisibleHint(true);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if(fragment != null)
{
ft.hide(fragment);
fragment.setUserVisibleHint(false);
}
}
While I still do not know why my code before was not working - I did find that adding the tab into the specified position with setSelected = true would indeed make it appear.
//set up tabs
actionBar.addTab(actionBar.newTab()
.setText("Input Trip")
.setTabListener(new CustomTabListener<InputNewTripFragment>(inputNewTripFragment,this,InputNewTripFragment.class)),0);
actionBar.addTab(actionBar.newTab()
.setText("View Trip Footprint")
.setTabListener(new CustomTabListener<FoodMilesFragment>(calcFoodMilesFragment,this,FoodMilesFragment.class)),1);
actionBar.addTab(actionBar.newTab()
.setText("Past Trips")
.setTabListener(new CustomTabListener<TripHistoryFragment>(tripHistoryFragment,this,TripHistoryFragment.class)),2);
actionBar.addTab(actionBar.newTab()
.setText("Trip Map")
.setTabListener(new CustomTabListener<ResultsMapFragment>(resultsMapFragment,this,ResultsMapFragment.class)),3);
//quickly pre-load the Food Miles Trip Footprint
actionBar.setSelectedNavigationItem(1);
actionBar.addTab(actionBar.newTab()
.setText("Set Current Location")
.setTabListener(new CustomTabListener<SetCurrentLocationFragment>(currLocFragment,this,SetCurrentLocationFragment.class)),0,true);
Related
I have an app built using TabBarSherlock and the Support library to add ActionBar support to pre 3.0 devices. I can't remember what tutorial I followed to create the Tabs and the Listener but I have the following code.
Firstly creating the Tabs (Inside a SherlockFragmentActivity):
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
/*--------Setup News Tab--------*/
Tab tab1 = actionBar.newTab()
.setText("News")
.setTabListener(new TabListener<TabFragment>(
this, "tab1", TabFragment.class));
Bundle newsBundle = new Bundle();
newsBundle.putInt("news_id", newsID);
tab1.setTag(newsBundle);
actionBar.addTab(tab1);
/*------------------------------*/
// This is repeated 3 more times to total 4 Tabs.
Then I have a classCalled TabListener which is used in each of these Tabs to detect when they have been selected.
public class TabListener<T extends Fragment> implements ActionBar.TabListener{
private TabFragment mFragment;
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
public TabListener(Activity activity, String tag, Class<T> clz) {
mActivity = activity;
mTag = tag;
mClass = clz;
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// Check if the fragment is already initialised
if (mFragment == null) {
Log.v("FRAGMENT", "FRAGMENT NEEDS TO BE CREATED");
mFragment = (TabFragment) Fragment.instantiate(mActivity, mClass.getName(), (Bundle)tab.getTag());
ft.add(android.R.id.content, mFragment, mTag);
} else {
Log.v("FRAGMENT", "FRAGMENT ALREADY CREATED");
ft.show(mFragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
ft.hide(mFragment);
}
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
With the class TabFragment containing a ViewPager for each Tab. My issue is that when selecting a Tab other than the first one the content inside the Fragment does not show. From the logs in place when the Fragment is initialised I can tell the views are being created just not being shown, it's just a blank area showing the background.
Instead of using show() and hide(), use attach() and detach(). Using show/hide does not remove the view hierarchy from the screen, simply hides it, so there might be issues related to that.
You are not detaching fragment rather you are just hiding it. so you should detach it so that other fragment should be attached in your onTabUnSelected.
FragmentManager will automatically restore whatever fragment (and history) was currently displayed upon a configuration change. Call findFragmentByTag to see if an instance of the target fragment already exists before creating and attaching a new instance.
Example:
public void onTabSelected(Tab tab, FragmentTransaction ft) {
SherlockFragment preInitializedFragment = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag);
// Check if the fragment is already initialized
if (mFragment == null && preInitializedFragment == null) {
// If not, instantiate and add it to the activity
mFragment = (SherlockFragment) SherlockFragment.instantiate(mActivity, mClass.getName());
ft.add(android.R.id.content, mFragment, mTag);
} else if (mFragment != null) {
// If it exists, simply attach it in order to show it
ft.attach(mFragment);
} else if (preInitializedFragment != null) {
ft.attach(preInitializedFragment);
mFragment = preInitializedFragment;
}
}
and you onTabUnSelected should be like this
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
// Detach the fragment, because another one is being attached
ft.detach(mFragment);
}
}
Content is empty on tab bar then write below code
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(actionBar.NAVIGATION_MODE_STANDARD);
I am implementing tabs in my activity.
I have 5 tabs and every tab contains a listview (i get the content of the listview through asynctask)
That's the image:
Now Codes:
mViewPager
.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
ab.setSelectedNavigationItem(position);
}
});
this.getSherlockActivity().getSupportActionBar().removeAllTabs();
ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
com.actionbarsherlock.app.ActionBar.Tab tab1 = ab
.newTab()
.setText("Samsung")
.setTabListener(
new TabListener<SamsungLB>(this.getSherlockActivity(),
"tabone", SamsungLB.class));
com.actionbarsherlock.app.ActionBar.Tab tab2 = ab
.newTab()
.setText("HTC")
.setTabListener(
new TabListener<HTCLB>(this.getSherlockActivity(),
"tabtwo", HTCLB.class));
com.actionbarsherlock.app.ActionBar.Tab tab3 = ab
.newTab()
.setText("LG")
.setTabListener(
new TabListener<LGLB>(this.getSherlockActivity(),
"tabthree", LGLB.class));
com.actionbarsherlock.app.ActionBar.Tab tab4 = ab
.newTab()
.setText("Sony")
.setTabListener(
new TabListener<SonyLB>(this.getSherlockActivity(),
"tabfour", SonyLB.class));
com.actionbarsherlock.app.ActionBar.Tab tab5 = ab
.newTab()
.setText("Search")
.setTabListener(
new TabListener<SearchLB>(this.getSherlockActivity(),
"tabfive", SearchLB.class));
ab.addTab(tab1);
ab.addTab(tab2);
ab.addTab(tab3);
ab.addTab(tab4);
ab.addTab(tab5);
return rootView;
}
#SuppressLint("NewApi")
public static class TabListener<T extends SherlockFragment> implements
ActionBar.TabListener {
private Fragment mFragment;
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
public TabListener(Activity activity, String tag, Class<T> clz) {
mActivity = activity;
mTag = tag;
mClass = clz;
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (mFragment == null) {
mFragment = Fragment.instantiate(mActivity, mClass.getName());
ft.add(android.R.id.content, mFragment, mTag);
} else {
ft.attach(mFragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
ft.detach(mFragment);
}
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
public void onTabReselected(Tab arg0,
android.app.FragmentTransaction arg1) {
}
#SuppressLint("NewApi")
public void onTabSelected(Tab arg0, android.app.FragmentTransaction arg1) {
mViewPager.setCurrentItem(arg0.getPosition());
}
public void onTabUnselected(Tab arg0,
android.app.FragmentTransaction arg1) {
}
#Override
public void onTabSelected(com.actionbarsherlock.app.ActionBar.Tab tab,
FragmentTransaction ft) {
// TODO Auto-generated method stub
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(
com.actionbarsherlock.app.ActionBar.Tab tab,
FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabReselected(
com.actionbarsherlock.app.ActionBar.Tab tab,
FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
Basically, every tab have a listview that fills through AsyncTask. i get the results through JSON And parse them. later on i parse the images through imageloader.
Why it's lagging???
Specially when i change from LG TO HTC. (Even there the application closes sometimes!).
thanks your help will be appreciated :)
UPDATE: All tabs are using the same layout file.
CODES:
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/listview1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="false" />
Kindly help.
As you are using many listviews, there are multiple causes that can slow down your performance..
How are you using adapter, eg: inflating a new view without using recycled convert view.
Improper layout XML declaration on list item, eg: using very complicated layout.
If you are doing a refresh every time you swipe a page, ViewPager.setOffscreenPageLimit(int limit) can prevent a reload while consuming more memory.
And if you're saying your application closes, you should have some stack trace available, posting it up helps us to identify the error.
i have the following activity which produced 3 tabs, and put fragment in each one of them.
public class ClientActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tabA = bar.newTab().setCustomView(R.layout.tab_a_layout);
ActionBar.Tab tabB = bar.newTab().setCustomView(R.layout.tab_b_layout);
ActionBar.Tab tabC = bar.newTab().setCustomView(R.layout.tab_c_layout);
Fragment fragmentA = new firstTab();
Fragment fragmentB = new secondTab();
Fragment fragmentC = new thirdTab();
tabA.setTabListener(new MyTabsListener(fragmentA));
tabB.setTabListener(new MyTabsListener(fragmentB));
tabC.setTabListener(new MyTabsListener(fragmentC));
bar.addTab(tabA);
bar.addTab(tabB);
bar.addTab(tabC);
}
protected class MyTabsListener implements ActionBar.TabListener {
private Fragment fragment;
public MyTabsListener(Fragment fragment)
{
this.fragment = fragment;
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft)
{
ft.add(R.id.fragment_place, fragment, null);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.remove(fragment);
}
}
}
in the first fragment (tabA) i have listview and listener which replacing the fragment on click.
when i am clicking on the second tab (after selecting line on the listview on tabA), the listener adding the tab instead of replacing it.
it happens because the TabUnsellected is removing the wrong fragment (it was first_tab, but replaced to test_tab on the listview selecting row).
how can i use the remove option on the ft on TabUnselected to remove the CURRENT fragment on the tab, assuming i have always 1 fragment on each tab?
Thanks
Fixed it by changing from ft.add to ft.replace on the TabSelected:
ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment_place, fragment);
ft.commit();
I have a Fragment Activity which holds three fragments.
public class MainActivity extends SherlockFragmentActivity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tab1 = bar.newTab();
ActionBar.Tab tab2 = bar.newTab();
ActionBar.Tab tab3 = bar.newTab();
tab1.setText("");
tab1.setIcon(R.drawable.abs__ic_menu_share_holo_dark);
tab2.setText("");
tab2.setIcon(R.drawable.abs__ic_voice_search);
tab3.setText("");
tab3.setIcon(R.drawable.abs__ic_cab_done_holo_dark);
if (savedInstanceState == null) {
tab1.setTabListener(new MyTabListener());
tab2.setTabListener(new MyTabListener());
tab3.setTabListener(new MyTabListener());
bar.addTab(tab1);
bar.addTab(tab2);
bar.addTab(tab3);
}
}
private class MyTabListener implements ActionBar.TabListener {
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
switch (tab.getPosition()) {
case 0:
FeedsActivity frag = new FeedsActivity();
ft.replace(android.R.id.content, frag);
return;
case 1:
ProfileActivity frag2 = new ProfileActivity();
ft.replace(android.R.id.content, frag2);
return;
case 2:
MyMemoirsActivity frag3 = new MyMemoirsActivity();
ft.replace(android.R.id.content, frag3);
return;
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
}
And here is first Fragment,
public class FeedsActivity extends SherlockFragment {
public static String[] MainCategory;
public static String[] MainCategoryId;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup group,
Bundle saved) {
setRetainInstance(true);
return inflater.inflate(R.layout.activity_feeds, group, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
new GetMainCategory(getActivity()).execute();
}
}
When I select second tab and then select first tab the async task in first fragment is called again.How can I retain state of first fragment so that its view is created once? I have used setRetainInstance(true) but didnt work.
I solved this issue by using show and hide instead of attach and detach.
private class MyTabListener implements ActionBar.TabListener {
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
switch (tab.getPosition()) {
case 0:
if (frag1 == null) {
// If not, instantiate and add it to the activity
frag1 = Fragment.instantiate(getApplicationContext(),
FeedsActivity.class.getName());
ft.add(android.R.id.content, frag1, "Feeds");
} else {
// If it exists, simply attach it in order to show it
ft.show(frag1);
}
return;
case 1:
if (frag2 == null) {
// If not, instantiate and add it to the activity
frag2 = Fragment.instantiate(getApplicationContext(),
ProfileActivity.class.getName());
ft.add(android.R.id.content, frag2, "Profile");
} else {
// If it exists, simply attach it in order to show it
ft.show(frag2);
}
return;
case 2:
if (frag3 == null) {
// If not, instantiate and add it to the activity
frag3 = Fragment.instantiate(getApplicationContext(),
History.class.getName());
ft.add(android.R.id.content, frag3, "History");
} else {
// If it exists, simply attach it in order to show it
ft.show(frag3);
}
return;
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
if (frag1 != null) {
// Detach the fragment, because another one is being attached
switch (tab.getPosition()) {
case 0:
ft.hide(frag1);
return;
case 1:
ft.hide(frag2);
return;
case 2:
ft.hide(frag3);
return;
}
}
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
The proper way to use TabListener is this :
#Override
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(android.R.id.content, mFragment, mTag);
} else {
// If it exists, simply attach it in order to show it
ft.attach(mFragment);
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
// Detach the fragment, because another one is being attached
ft.detach(mFragment);
}
}
#override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// User selected the already selected tab. Usually do nothing.
}
Basically you need to check if that's the first time when your Fragment is being initialised. If not, you should add it to your screen and when the user unselect a tab you should detach the current visible fragment and add the new one. That's the way it should work. You don't need to create a new instance of Fragment everytime user click the tab.
I have an Android project with Sherlock ActionBar and Support Library.
In the onCreate of SherlockFragmentActivity I initialized ActionBar with 2 tabs:
private void configureActionBar(){
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tab = actionBar.newTab()
.setText("Events")
.setTabListener(new TabListener<SampleListFragment>(
this, "events", SampleListFragment.class));
actionBar.addTab(tab);
tab = actionBar.newTab()
.setText("Map")
.setTabListener(new TabListener<SupportMapFragment>(
this, "map", SupportMapFragment.class));
actionBar.addTab(tab);
}
The problem is when I go back to the first tab, the screen is black with grayed Map controls. If I turn off\on the device screen, the Map completely removes and everyting is fine.
TabListener implementation is from the Google Manual:
public class TabListener<T extends Fragment> implements ActionBar.TabListener {
private Fragment mFragment;
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
/** 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 TabListener(Activity activity, String tag, Class<T> clz) {
mActivity = activity;
mTag = tag;
mClass = clz;
}
/* The following are each of the ActionBar.TabListener callbacks */
public void onTabSelected(ActionBar.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(android.R.id.content, mFragment, mTag);
} else {
// If it exists, simply attach it in order to show it
ft.attach(mFragment);
}
}
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
// Detach the fragment, because another one is being attached
ft.detach(mFragment);
}
}
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
// User selected the already selected tab. Usually do nothing.
}
}
I came across with similar issue once when implementing the SupportMapFragment with a SlidingMenu, after searching forums I found that it was an issue with surfaceView and that it could be fixed by setting the map transparent with this method:
private void setMapTransparent(ViewGroup group) {
int childCount = group.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = group.getChildAt(i);
if (child instanceof ViewGroup) {
setMapTransparent((ViewGroup) child);
} else if (child instanceof SurfaceView) {
child.setBackgroundColor(0x00000000);
}
}
}
Just call that method on your SupportMapFragment's onCreateView.