Tab and fragments no support intents - android

Hi I have a problem with tab+fragment, here frist I have the class which will create the tab:
public class TestSwipeABActivity extends FragmentActivity {
FragmentTransaction transaction;
static ViewPager mViewPager;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Fragment tabOneFragment = new TabOne();
Fragment tabTwoFragment = new TabTwo();
PagerAdapter mPagerAdapter = new PagerAdapter(getSupportFragmentManager());
mPagerAdapter.addFragment(tabOneFragment);
mPagerAdapter.addFragment(tabTwoFragment);
//transaction = getSupportFragmentManager().beginTransaction();
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mPagerAdapter);
mViewPager.setOffscreenPageLimit(2);
mViewPager.setCurrentItem(0);
mViewPager.setOnPageChangeListener(
new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// When swiping between pages, select the
// corresponding tab.
getActionBar().setSelectedNavigationItem(position);
}
});
ActionBar ab = getActionBar();
ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
Tab tab1 = ab.newTab().setText("Tab One").setTabListener(new TabListener<TabOne>(
this, "tabone", TabOne.class));
Tab tab2 = ab.newTab().setText("Tab Two").setTabListener(new TabListener<TabTwo>(
this, "tabtwo", TabTwo.class));
ab.addTab(tab1);
ab.addTab(tab2);
}
public static 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(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(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
// Detach the fragment, because another one is being attached
ft.detach(mFragment);
}
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// User selected the already selected tab. Usually do nothing.
}
public void onTabReselected(Tab arg0,
android.app.FragmentTransaction arg1)
{
// TODO Auto-generated method stub
}
public void onTabSelected(Tab arg0, android.app.FragmentTransaction arg1)
{
// TODO Auto-generated method stub
mViewPager.setCurrentItem(arg0.getPosition());
}
public void onTabUnselected(Tab arg0,
android.app.FragmentTransaction arg1)
{
// TODO Auto-generated method stub
}
}
public class PagerAdapter extends FragmentPagerAdapter {
private final ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
public PagerAdapter(FragmentManager manager) {
super(manager);
}
public void addFragment(Fragment fragment) {
mFragments.add(fragment);
notifyDataSetChanged();
}
#Override
public int getCount() {
return mFragments.size();
}
#Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
}
}
And then here is the fragment for each tab, for example the two one:
public class TabTwo extends Fragment
{
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.tabtwo, container, false);
Button Activity1= (Button) view.findViewById(R.id.button1);
Activity1.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Intent intent = new Intent().setClass(this,ABActivity.class);
startActivity(intent);
}
});
return view;
}
}
The error was: The method setClass(Context, Class<?>) in the type Intent is not applicable for the arguments (new View.OnClickListener(){},
Class<ABActivity>)
I try out changing the context to TabTwo.this, tabtwo.getcontext.this, but nothing, eclipse says to change .setclassName but doesnt work.
If you could help... THANKS!!!

Try this
Intent intent = new Intent(getActivity(),ABActivity.class);
startActivity(intent );

HI I just have a solution:
public void onClick(View view) {
Activity activity = getActivity();
Intent intent = new Intent().setClass(activity, ABActivity.class);
startActivity(intent);
}
Explanation: "Another difference is that a Fragment is not a subclass of Context. This means that a Fragment can not be launched as a component inside your app and therefore always has to live inside of an Activity. This also means that whenever you need a Context inside of a Fragment, you need to get access to the parent Activity. You can do this by using the getActivity() method as we have done in the Fragment button's OnClickListener callback. You need to watch out because getActivity() can return null depending on where the Fragment is in the Activity's lifecycle. So, you should also include a check to see if the Activity is null before you use it."
FROM: http://neilgoodman.net/2012/01/29/working-with-fragments-on-android-part-1/

Related

Android refresh a fragment list from its parent activity

I have a main activity which contains the action bar with 3 menu buttons in it.
I then have a fragment within this main activity which has a list.
I would like to be able to refresh the list in the fragment from the main activity, when one of the menu buttons is clicked, or preferably just removed all the rows from the list.
Any help is appreciated.
Thanks.
public class Favourite extends SherlockFragmentActivity {
ActionBar actionBar;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.favourite);
actionBar = getSupportActionBar();
actionBar.setDisplayShowTitleEnabled(false);
BitmapDrawable bg = (BitmapDrawable)getResources().getDrawable(R.drawable.actionbar_bg);
bg.setTileModeX(TileMode.REPEAT);
getSupportActionBar().setBackgroundDrawable(bg);
getSupportActionBar().setIcon(R.drawable.favourite_title);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tabAll = actionBar.newTab();
ActionBar.Tab tabfavs = actionBar.newTab();
ActionBar.Tab tabhist = actionBar.newTab();
tabAll.setText("all");
tabfavs.setText("favs");
tabhist.setText("hist");
tabAll.setTabListener(new MyTabListener());
tabfavs.setTabListener(new MyTabListener());
tabhist.setTabListener(new MyTabListener());
actionBar.addTab(tabAll);
actionBar.addTab(tabfavs);
actionBar.addTab(tabhist);
try{
}
catch(Exception e)
{
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.actionbar_itemlist_favourite, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.history:
break;
case R.id.favourite:
Intent favAct = new Intent(this, Favourite.class);
startActivity(favAct);
break;
case R.id.delete:
///I WANT TO BE ABLE TO REFRESH FRAGMENTLIST FROM HERE
}
return true;
}
}
class MyTabListener implements ActionBar.TabListener {
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if(tab.getPosition()==0)
{
FavouriteAllWords frag = new FavouriteAllWords();
ft.replace(android.R.id.content, frag);
}
else if(tab.getPosition()==1)
{
FavouriteFavWords frag = new FavouriteFavWords();
ft.replace(android.R.id.content, frag);
}
else if(tab.getPosition()==2)
{
FavouriteHistWords frag = new FavouriteHistWords();
ft.replace(android.R.id.content, frag);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
////////////////////MY LIST FRAGMENT CLASS
public class FavouriteAllWords extends ListFragment {
ArrayAdapter<String> adapter;
List<String> stringOfFavWords;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup group, Bundle saved)
{
adapter = new ArrayAdapter<String>(
inflater.getContext(), R.layout.row, stringOfFavWords);
setListAdapter(adapter);
return super.onCreateView(inflater, group, saved);
}
#Override
public void onActivityCreated (Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
}
}
You can easily achieve this using INTERFACE
MainActivity.java
public class MainActivity extends Activity {
public FragmentRefreshListener getFragmentRefreshListener() {
return fragmentRefreshListener;
}
public void setFragmentRefreshListener(FragmentRefreshListener fragmentRefreshListener) {
this.fragmentRefreshListener = fragmentRefreshListener;
}
private FragmentRefreshListener fragmentRefreshListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button b = (Button)findViewById(R.id.btnRefreshFragment);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(getFragmentRefreshListener()!=null){
getFragmentRefreshListener().onRefresh();
}
}
});
}
public interface FragmentRefreshListener{
void onRefresh();
}
}
MyFragment.java
public class MyFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = null; // some view
/// Your Code
((MainActivity)getActivity()).setFragmentRefreshListener(new MainActivity.FragmentRefreshListener() {
#Override
public void onRefresh() {
// Refresh Your Fragment
}
});
return v;
}
}
Just make your update/refresh method public and call it from your Activity.
OR
Use LocalBroadcastManager or EventBus to send event from your Activity, and by subscribing to this event in a Fragment - react to it and call refresh/update method.
Your activity can call methods in the fragment by acquiring a reference to the Fragment.
(1) Provide a tag when you add your fragment.
transaction.add(R.id.fragment_container, myFragment, "myfragmentTag");
(2) In your hosting activity you can find the fragment and have access to it's methods.
FragmentManager fm = getSupportFragmentManager();
myFragment f = (myFragment) fm.findFragmentByTag("myfragmentTag");
f.refreshAdapter()
(3) refreshAdapter() could now call adapter.notifyDataSetChanged().
This is one of the recommended ways to communicate up to a fragment.
The interface implementation is mainly for communicating back to the activity.
Biraj Zalavadia's answer is 100% right, you will call nay fragment methods from using interface....
this interface methods is running without error...
use this in MainActivity above oncreate
private FragmentRefreshListener fragmentRefreshListener;
public FragmentRefreshListener getFragmentRefreshListener() {
return fragmentRefreshListener;
}
public void setFragmentRefreshListener(
FragmentRefreshListener fragmentRefreshListener) {
this.fragmentRefreshListener = fragmentRefreshListener;
}
inside of Activity
private void refreshcall(String result2) {
// TODO Auto-generated method stub
if (getFragmentRefreshListener() != null) {
getFragmentRefreshListener().onRefresh(result2);
}
}
and put this in needed Fragment
private FragmentRefreshListener fragmentRefreshListener;
public FragmentRefreshListener getFragmentRefreshListener() {
return fragmentRefreshListener;
}
public void setFragmentRefreshListener(
FragmentRefreshListener fragmentRefreshListener) {
this.fragmentRefreshListener = fragmentRefreshListener;
}
Communicating with Other Fragments
http://developer.android.com/training/basics/fragments/communicating.html
This can also be used to communicate between an Activity and a Fragment.
When you click on ActionBar any Button then call interface to refresh the ListFragment. Because in java interface is used for inter-communication.
In Kotlin
Get the list of Support Fragment from the activity and check Instance and then call fragment function
val fragments = supportFragmentManager.fragments
for (fragment in fragments) {
if (fragment is HomeCategoriesFragment) {
fragment.updateAdapter() // Define function in Fragment
}
}

How to manage some items of a fragment in another class from an ActionBarActivity, Android

First off, you have to forgive me, because my English is very bad.
I'll try to explain the issue:
I have an ActionBarActivity with two pages (ViewPager).
Every page has a Fragment.
My problem is: how to use the elements of each Fragment from this ActionBarActivity?
My code is this:
ActionBarActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.manage_devices);
mActionbar = getSupportActionBar();
mActionbar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
mPager = (ViewPager) findViewById(R.id.pager);
FragmentManager fm = getSupportFragmentManager();
MyFragmentPagerAdapter fragmentPagerAdapter = new MyFragmentPagerAdapter(fm);
mPager.setAdapter(fragmentPagerAdapter);
mActionbar.setDisplayShowTitleEnabled(true);
ActionBar.TabListener tabListener = new ActionBar.TabListener() {
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
mPager.setCurrentItem(tab.getPosition());}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {}
};
mActionbar.addTab(mActionbar.newTab().setText("SENSORS").setTabListener(tabListener));
mActionbar.addTab(mActionbar.newTab().setText("SIGNALS").setTabListener(tabListener));
/** Defining a listener for pageChange */
ViewPager.SimpleOnPageChangeListener pageChangeListener = new ViewPager.SimpleOnPageChangeListener(){
**#Override
public void onPageSelected(int position) {
super.onPageSelected(position);
if(position == 0 & !hecho){
currView = mPager.getChildAt(mPager.getCurrentItem());
DevicesListView = (ListView) currView.findViewById(R.id.DevicesListView);
DevicesListView.setAdapter(DevicesAdapter);
DevicesListView.setOnItemClickListener(DeviceOnItemClickListener);
hecho = true;}
else if(!hecho){
mGraph = (GraphView)findViewById(R.id.graph);
}
mActionbar.setSelectedNavigationItem(position);
}**
};
/** Setting the pageChange listener to the viewPager */
mPager.setOnPageChangeListener(pageChangeListener);
}
To get a Listview, I access it in OnPageSelected.
But this is bad for me, because I need to change a page for getting the Listview and build it.
ManageFragment.java
public class ManageFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d("","Entra");
return inflater.inflate(R.layout.manage_fragment, null);
}
}
My Listview is in the manage_fragment layout.
This can help: Illustration
Thank you very much!!!
If your fragment already created you can just use findViewById() in your activity and just find the view you want.
So you should inform your activity that the fragment view already created through an interface for example:
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnViewCreatedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
}
}
And then call the interface after Fragment's onCreateView.

Play with fragments in onTabSelected

Dears,
I searched for this issue for more than a day but with no luck.
I implement exactly the code posted here:
Adding Navigation Tabs
My code for onTabSelected look like:
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.alert_fragment_container, mFragment, mTag);
} else {
// If it exists, simply attach it in order to show it
ft.attach(mFragment);
}
// prepare adapter for ExpandableListView
Log.i("After Adapter Created", "Passed");
final ExpandableListAdapter expListAdapter = new AlertsAdapter(
mActivity, myAlerts, violations);
Log.i("After Adapter Initialized", "Passed");
((MyCustomFragment)mFragment).violations.setAdapter(expListAdapter);
}
The code is working fine till last line, where I need to set the adapter for public static list initialized in MyCustomFragment in onCreateView, here my code for fragment:
public class MyCustomFragment extends Fragment {
public MyCustomFragment() {
}
public static ExpandableListView violations;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_alerts_poi, container, false);
violations = (ExpandableListView) rootView.findViewById(R.id.POIAlertList);
Log.i("onCreateView POI", "Called");
return rootView;
}
}
It give Null pointer error. With my debugging logs, I notice that this log Log.i("onCreateView POI", "Called"); appears after this Log.i("After Adapter Initialized", "Passed");. This means that I'm trying to set the adapter for a fragment isn't initialized yet.
This is the exact problem I'm face, I need to fed the ExpandableListView with data based on Tab selection in onTabSelected.
What I'm doing wrong? What is the best solution?
Regards,
It seems that you need a ViewPager, I just implemented a navigation tabs few days ago, here is my code, it navigates between 4 fragments:
public class MainActivity extends FragmentActivity implements ActionBar.TabListener{
private ActionBar actionBar;
private ViewPager mViewPager;
private AppSectionsPagerAdapter mAppSectionsPagerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAppSectionsPagerAdapter = new AppSectionsPagerAdapter(getSupportFragmentManager());
actionBar=getActionBar();
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mAppSectionsPagerAdapter);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
actionBar.addTab(actionBar.newTab().setIcon(R.drawable.icon1).setTabListener(this));
actionBar.addTab(actionBar.newTab().setIcon(R.drawable.icon2).setTabListener(this));
actionBar.addTab(actionBar.newTab().setIcon(R.drawable.icon3).setTabListener(this));
actionBar.addTab(actionBar.newTab().setIcon(R.drawable.icon4).setTabListener(this));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// TODO Auto-generated method stub
getMenuInflater().inflate(R.menu.action_menu, menu);
return true;
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
And here is the adapter:
public class AppSectionsPagerAdapter extends FragmentPagerAdapter {
public AppSectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
switch (i) {
case 0:
return new Fragment1();
case 1:
return new Fragment2();
case 2:
return new Fragment3();
case 3:
return new Fragment4();
}
return null;
}
#Override
public int getCount() {
return 4;
}
}
Have a look # this Tablayout.onTabselected for latest API updates. ActionBar.TabListener is a old implementation.

Android: ListView annoyingly scrolling to top when changing between tabs and back

I have a ListView inside of a Fragment attached to a CursorAdapter. The Fragment has setRetainInstance(true). Under the Fragment's onCreate() method, I instantiate the CursorAdapter (storing it in variable adapter). I then call listView.setAdapter(adapter) under my Fragment's onCreateView method. The Cursor in the CursorAdapter is loaded by a CursorLoader. Inside my LoaderCallbacks' onLoadFinished(), I call adapter.swapCursor(cursor).
In sum: Everything seems to be in place such that the ListView should not scroll to top when changing between tabs and back. But it still does! Could I be missing something?
Here's some code.
Fragment
public class Home extends Fragment{
...
private HomeFeedAdapter adapter; // HomeFeedAdapter extends CursorAdapter
private AutoQuery autoQuery; // AutoQuery extends LoaderCallbacks<Cursor>
... // (See inner class, at the end)
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
if(adapter == null)
adapter = new HomeFeedAdapter(getActivity(), null);
if(autoQuery == null)
autoQuery = new AutoQuery();
getLoaderManager().initLoader(LOADER_INITIAL, null, autoQuery);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Layout
View v = inflater.inflate(R.layout.home, container, false);
l = (ListView) v.findViewById(R.id.listview);
l.setAdapter(adapter);
return v;
}
private class AutoQuery implements LoaderCallbacks<Cursor>{
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
...
return new CursorLoader(getActivity(), uri,
null, null, null, null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
adapter.swapCursor(cursor);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.swapCursor(null);
}
}
}
Activity
public class MainActivity extends SherlockFragmentActivity {
...
private class TabsListener implements ActionBar.TabListener {
private Fragment fragment;
private String tag;
public TabsListener(Fragment fragment, String tag) {
this.fragment = fragment;
this.tag = tag;
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// Do nothing
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
ft.replace(R.id.fragment_container, fragment, tag);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.remove(fragment);
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Layout
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setHomeButtonEnabled(false);
getSupportActionBar().setDisplayShowTitleEnabled(false);
setContentView(R.layout.activity_main);
// Loads fragment
Fragment fHome, fActivity, fProfile;
if((fHome = getSupportFragmentManager().findFragmentByTag(HOME)) == null) fHome = new Home();
if((fActivity = getSupportFragmentManager().findFragmentByTag(ACTIVITY)) == null) fActivity = new FriendsList();
if((fProfile = getSupportFragmentManager().findFragmentByTag(PROFILE)) == null) fProfile = new Profile();
ActionBar.Tab tab;
tab = getSupportActionBar().newTab();
tab.setTabListener(new TabsListener(
fHome,
HOME
));
getSupportActionBar().addTab(tab, false);
tab = getSupportActionBar().newTab();
tab.setTabListener(new TabsListener(
fActivity,
ACTIVITY
));
getSupportActionBar().addTab(tab, false);
tab = getSupportActionBar().newTab();
tab.setTabListener(new TabsListener(
fProfile,
PROFILE
));
getSupportActionBar().addTab(tab, false);
...
}
}
With Greg Giacovelli's help in leading me in the right direction, I've found a solution to my problem.
I'll begin with a disclaimer that I don't quite understand how ListView positions are saved. My ListView instance is recreated every time that my Fragment's onCreateView() is called. This happens when the screen rotates, for example. And yet, in the specific case of screen rotations, even though onCreateView() is called and thus the ListView is reinstantiated, the ListView's state is nonetheless restored. So if the ListView is being recreated, something else must be telling it what its position previously was... and I don't know what that is. I think that it's attributable to the machinery of setRetainInstance(true).
But let's look at my main issue: Why did the ListView scroll to top between tab changes? As Greg suggested, it was because I was re-adding the Fragment with replace(), and thus destroying my Fragment and re-creating every time the user flipped to another tab and back.
My solution was to check if the tab was already added; if so, then not add it; else, add it. Then, when the user clicks out of a tab, I simply detach the fragment (not remove it), and attach a new one. This way the unselected tab's Fragment is still alive, though detached.
// Tabs listener
private class TabsListener implements ActionBar.TabListener {
private Fragment fragment;
private String tag;
public TabsListener(Fragment fragment, String tag) {
this.fragment = fragment;
this.tag = tag;
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
if(fragment instanceof ScrollableToTop) ((ScrollableToTop) fragment).scrollToTop();
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if(!fragment.isAdded()){
ft.add(R.id.fragment_container, fragment, tag);
}
ft.attach(fragment);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.detach(fragment);
}
}

Sherlock tabs not working on orientation change

I managet to set up three tabs using Sherlock ActionBar. The only problem is that when orientation is changed, tabs can not be tapped any more. It seem like the onTabSelected() is not called. Example: I am in portrait and the tab2 is selected. I change into lanscape. Tab2 is still selected, I tap tab3 but nothing happens. Then when I go back to portrait again, tab3 is shown. I am testing in Android 2.3.6.
This is the main activity:
public class Activity_Main extends SherlockFragmentActivity {
ActionBar.Tab tab1, tab2, tab3;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTabs();
}
void setTabs(){
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
tab1 = actionBar.newTab();
tab2 = actionBar.newTab();
tab3 = actionBar.newTab();
tab1.setText("Week");
tab2.setText("Today");
tab3.setText("ToDo");
tab1.setTabListener(new TabListener<Fragment_Start_Week>(this, "week", Fragment_Start_Week.class));
tab2.setTabListener(new TabListener<Fragment_Start_Today>(this, "today", Fragment_Start_Today.class));
tab3.setTabListener(new TabListener<Fragment_Start_Todo>(this, "todo", Fragment_Start_Todo.class));
}
private class TabListener<T extends SherlockFragment> implements com.actionbarsherlock.app.ActionBar.TabListener{
private SherlockFragment 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(Tab tab, FragmentTransaction ft) {
SherlockFragment preInitializedFragment = (SherlockFragment) ((FragmentActivity) 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;
}
}
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) {
// TODO Auto-generated method stub
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
}
This is a fragment:
public class Fragment_Start_Week extends SherlockFragment implements OnClickListener{
void create_table() {
...
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup group, Bundle saved)
{
return inflater.inflate(R.layout.fragment_start_week, group, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
create_table();
}
#Override
public void onClick(View view) {
...
}
}
TIA
After a lot of trial and errors I've found the following solution for this bug:
#Override
public void onConfigurationChanged(Configuration newConfig) {
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
super.onConfigurationChanged(newConfig);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
}
The trick is to change the navigation mode to list then change back to tabs.

Categories

Resources