I have 3 tabs in action bar, each tab is associated with a fragment. Each fragment has a ListView which is bind to a SimpleCursorAdapter. When the ListView item is clicked, it navigates to a detail activity, and there is a back button to go back. I expect the ListView get updated when I remove item in the detail activity.
The problem is (Assume the 3 tabs is A, B, C):
1) If I select item from A, and go to the detail page, remove this item, then go back to A, the ListView in tab A get updated, this is what I expect.
2) But if I select tab A, select B, select A again, then repeat the step in 1), the ListView is not updated.
I use the following code to navigate back in the detail activity:
getFragmentManager().popBackStackImmediate();
There is my TabListener:
public class TabListener<T extends Fragment> implements ActionBar.TabListener {
public TabListener(Activity activity, String tag, Class<T> clz) {
activity_ = activity;
tag_ = tag;
class_ = clz;
}
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction transaction) {
if (fragment_ == null) {
fragment_ = Fragment.instantiate(activity_, class_.getName());
transaction.add(android.R.id.content, fragment_, tag_);
} else {
transaction.add(android.R.id.content, fragment_, tag_);
}
}
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction transaction) {
if (fragment_ != null) {
transaction.remove(fragment_);
}
}
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction transaction) {
// User selected the already selected tab. Usually do nothing.
}
private Fragment fragment_;
private final Activity activity_;
private final String tag_;
private final Class<T> class_;
}
If you need anymore code, just tell me.
I resolved it.
Change the TabListener to:
public class TabListener<T extends Fragment> implements ActionBar.TabListener {
public TabListener(Activity activity, String tag, Class<T> clz) {
activity_ = activity;
tag_ = tag;
class_ = clz;
}
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction transaction) {
if (fragment_ == null) {
fragment_ = Fragment.instantiate(activity_, class_.getName());
transaction.add(android.R.id.content, fragment_, tag_);
} else {
// transaction.add(android.R.id.content, fragment_, tag_);
transaction.show(fragment_);
}
}
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction transaction) {
if (fragment_ != null) {
transaction.hide(fragment_);
}
}
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction transaction) {
if (fragment_ != null) {
transaction.hide(fragment_);
transaction.show(fragment_);
}
}
private Fragment fragment_;
private final Activity activity_;
private final String tag_;
private final Class<T> class_;
}
And in Fragment class's onResume event, re-select the tab.
public void onResume() {
super.onResume();
getActivity().getActionBar().setSelectedNavigationItem(getActivity().getActionBar().getSelectedNavigationIndex());
}
Related
I have 2 tabs in my app, using tablistner and I'm facing an issue when I'm navigating in a very specific situation to other tab and then navigating back to the first tab.
It happens after i load a fragment called "setFrom" from another fragment:
public void LoadSetFrom ()
{
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
SherlockFragment setFrag = new setFrom();
ft.replace(R.id.main_layout, setFrag, "setfrom");
ft.commit();
}
This "setFrom" fragment is one of my 2 tabs, after that I'm navigatin to the second tab and when I'm going back to "setFrom" the tabs navigation still appears but the fragment is totally blank.
I'm using TabListener that way:
public class TabListener<T extends SherlockFragment> implements com.actionbarsherlock.app.ActionBar.TabListener
{
private SherlockFragment mFragment;
private setFrom fromFragment;
private final SherlockFragmentActivity mActivity;
private final String mTag;
private final Class<T> mClass;
public TabListener(SherlockFragmentActivity activity, String tag, Class<T> clz) {
mActivity = activity;
mTag = tag;
mClass = clz;
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
SherlockFragment preInitializedFragment = (SherlockFragment)mActivity.getSupportFragmentManager().findFragmentByTag(mTag);
if (preInitializedFragment == null) {
mFragment = (SherlockFragment) SherlockFragment.instantiate(mActivity, mClass.getName());
ft.add(R.id.main_layout, mFragment, mTag);
}
else {
ft.attach(preInitializedFragment);
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null)
ft.detach(mFragment);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
After checking onTabSelected, "setFrom" is not null,it attached to the right fragment and it goes to ft.attach(preInitializedFragment) which is fine.
My question is why after the attach to the right fragment the view is still blank?
I was facing the same problem
Solved it by adding setRetainInstance(true); to my Fragment's onCreate
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.
I use ActionBar and use inner TabListener in the Activity:
public static class TabListener<T extends Fragment>
implements ActionBar.TabListener{
private final Activity myActivity;
private final String myTag;
private final Class<T> myClass;
public TabListener(Activity activity, String tag, Class<T> cls) {
myActivity = activity;
myTag = tag;
myClass = cls;
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// User selected the already selected tab. Usually do nothing.
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Fragment myFragment = myActivity.getFragmentManager().findFragmentByTag(myTag);
// Check if the fragment is already initialized
if (myFragment == null) {
// If not, instantiate and add it to the activity
myFragment = Fragment.instantiate(myActivity, myClass.getName());
myActivity.setTitle( myClass.getName());
ft.add(android.R.id.content, myFragment, myTag);
} else {
// If it exists, simply attach it in order to show it
myActivity.setTitle( myFragment.getClass().getName());
ft.attach(myFragment);
}
Log.i("current fragment", myFragment.getClass().toString());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
Fragment myFragment = myActivity.getFragmentManager().findFragmentByTag(myTag);
if (myFragment != null) {
// Detach the fragment, because another one is being attached
ft.detach(myFragment);
}
}
}
I need to switch another Fragment at the current tab from DialogFragment . I do it in common way like this:
Fragment newFragment = new ContactsArchiveFragment();
fragmentTransaction.replace(android.R.id.content, newFragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
But when I switch to another tab, my current Fragment(which was switched to) is not detached and displays above. How can I solve this?
Try This..
public void addFragment(Fragment fragment, boolean addToBackStack,
int transition) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(android.R.id.content, fragment);
ft.setTransition(transition);
if (addToBackStack)
ft.addToBackStack(null);
ft.commit();
}
You can use true first time, then change it to false
addFragment(newfragment, true, FragmentTransaction.TRANSIT_NONE);
I solved my issue, using this. Here's the solution:
public static class TabListener<T extends Fragment>
implements ActionBar.TabListener{
private final Activity myActivity;
private final String myTag;
private final Class<T> myClass;
private Fragment mFragment;
public TabListener(Activity activity, String tag, Class<T> cls) {
myActivity = activity;
myTag = tag;
myClass = cls;
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// User selected the already selected tab. Usually do nothing.
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// Fragment myFragment = myActivity.getFragmentManager().findFragmentByTag(myTag);
Fragment preInitializedFragment = (Fragment) myActivity.getFragmentManager().findFragmentByTag(myTag);
if (preInitializedFragment == null) {
mFragment = (Fragment) Fragment.instantiate(myActivity, myClass.getName());
ft.add(android.R.id.content, mFragment, myTag);
} else {
ft.attach(preInitializedFragment);
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
Fragment preInitializedFragment = myActivity.getFragmentManager().findFragmentByTag(myTag);
if (preInitializedFragment != null) {
ft.detach(preInitializedFragment);
} else if (mFragment != null) {
ft.detach(mFragment);
}
}
}
I have read alot on stackoverflow on fragments issues but I cant find a solution to my problem.
I have a Tabhost and when I change rotation of the device and then select another tab, the view from the first tab is also visible. So both tabs content is on top of each other.
I'm using a a custom tablistener and every tab is a fragment. I could bypass this with android:configChanges="keyboardHidden|orientation|screenSize"but this solution gave me a list of other problems and I read that this is a bad solution.
public class TabListener<T extends Fragment> implements ActionBar.TabListener {
private Fragment fragment;
private final FragmentActivity activity;
private final String tag;
private final Class<T> myClass;
private long id;
public TabListener(FragmentActivity a, String t, Class<T> c, long id) {
tag = t;
myClass = c;
activity = a;
this.id = id;
}
/** The following are each of the ActionBar.TabListener callbacks */
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// Check if the fragment is already initialized
if (fragment == null) {
fragment = Fragment.instantiate(activity, myClass.getName());
// Sends stored TimerClass id to fragment
if(id != 0) {
Bundle b = new Bundle();
b.putLong("id", id);
fragment.setArguments(b);
}
ft.add(android.R.id.content, fragment, tag);
} else { // If it exists, simply attach it in order to show it
ft.attach(fragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (fragment != null)
ft.detach(fragment);
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
editNameDialog();
}
}
I dont know it this should be handled in the fragment, the activity or in the TabListener. The tabs content is viewd correctly until I change the screens orientation.
I found parts of the answer here on stackoverflow.
Solution
This is how I solved the problem. In the tab listeners I put:
fragment = activity.getSupportFragmentManager().findFragmentByTag(tag);
in both onTabSelect() and onTabUnselect()
Select correct tab after orientation change
When the screen rotates the activity is recreated(?) we need to store the last selected tab index.
Save last selected tab (this goes in the activity):
#Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putInt("lastTab", actionBar.getSelectedNavigationIndex());
}
To load tab index, put this in onCreate() of the activity, this way we retreive the last tab index and selects it:
if (savedInstanceState != null) {
actionBar.selectTab(actionBar.getTabAt(savedInstanceState.getInt("lastTab")));
}
Initialize controllers in the fragment
To prevent the controls to diplay and behave odd I moved all controls inits in the fragment to onCreateView() like this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.timer, container, false);
initializeControls(v);
setSeekBars(v);
return v;
}
I hope this will help someone else out there.
I am trying to create a tab that displays a list on the left hand fragment and a detailed fragment on the right. When a user clicks a list item, the right hand fragment should change to the appropriate one.
I am new to android so I used a tutorial and I know I need to do something with the tablistener: public static class TabListener implements ActionBar.TabListener
{
private final Activity mActivity;
private final String mTag;
private final Class mClass;
private final Bundle mArgs;
private Fragment mFragment;
public TabListener(Activity activity, String tag, Class<T> clz) {
this(activity, tag, clz, null);
}
public TabListener(Activity activity, String tag, Class<T> clz, Bundle args) {
mActivity = activity;
mTag = tag;
mClass = clz;
mArgs = args;
// Check to see if we already have a fragment for this tab, probably
// from a previously saved state. If so, deactivate it, because our
// initial state is that a tab isn't shown.
mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag);
if (mFragment != null && !mFragment.isDetached()) {
ft = mActivity.getFragmentManager().beginTransaction();
ft.detach(mFragment);
ft.commit();
}
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (mFragment == null) {
mFragment = Fragment.instantiate(mActivity, mClass.getName(), mArgs);
ft.add(android.R.id.content, mFragment, mTag);
tabtag = 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) {
//Toast.makeText(mActivity, "Reselected!", Toast.LENGTH_SHORT).show();
}
}
Another good example of what I need would be something like the Gmail app, with a list on the left, detail on the right, and keeping the action bar (mine has tabs) on top.
I understand that this listener inflates a fragment for each tab clicked, but how do I inflate a layout that has two fragments in it?
Inflating a layout with two fragments is simple: you just specify the Class of each fragment in the layout. But you can't mix static (layout XML-defined) and dynamic Fragments. By which I mean, you can't dynamically instantiate a new Fragment in code and insert it into a View container (e.g., a LinearLayout) that was originally populated with Fragments in the XML.