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
Related
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());
}
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);
}
}
}
EDIT
I edited the previous question, wich i solved. Thanks a lot for the replies.
I have a gui with 3 tabs (News, Strategy and History), in one of them (News) i load an ExpandableListView and when the user clicks in one of the items from the list, it loads another fragment containg details from the selected item. I managed to replace the fragment in that tab with another fragment, using this code:
CategoryTab categories = new CategoryTab();//Fragment 2
FragmentManager manager = activity.getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(this.getId(), categories, "News");
//transaction.replace(android.R.id.content, categories, "News");
transaction.addToBackStack(null);
transaction.commit();
When the seconds fragment loads in the News tab, all the other tabs shows that fragment. I'm using this listener to manage tab navigation
public static class TabListener<T extends Fragment> implements ActionBar.TabListener {
private final Activity mActivity;
private final String mTag;
private final Class<T> 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()) {
FragmentTransaction 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);
} 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();
}
}
My question is ¿why all the tabs shows the same fragment when the replacement is done? and ¿how can i simulate a back button with the icon provided in the action bar, to load again fragment 1 in News Tab?
Any help will be appreciated
PD: Sorry for my english
Make sure you call getActivity() in or after onActivityCreated, as before then it will return null.
The Fragment will be attached to a null activity until onActivityCreated... that is, if you call getActivity() in onCreate or onCreateView, it will return null because the Activity hasn't been created yet. So make sure you have all of your calls to getActivity() in or after onActivityCreated
In my Android app I'm using an Action Bar with tabs to switch between fragments that display the content of the tabs. Everything is working fine until an orientation change: Then Android starts to draw the widgets on top of each other so that the contents of the fragments get mixed up. My TabListener:
private class TabListener implements ActionBar.TabListener {
private final Activity mActivity;
private final String mTag;
public TabListener(Activity activity, String tag) {
mActivity = activity;
mTag = tag;
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
Fragment mFragment = MyActivity.this.getSupportFragmentManager().findFragmentByTag(mTag);
if (mFragment == null) {
mFragment = new MyFragment();
ft.add(android.R.id.content, mFragment, mTag);
} else {
ft.attach(mFragment);
}
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
Fragment mFragment = MyActivity.this.getSupportFragmentManager().findFragmentByTag(mTag);
if (mFragment != null) {
ft.detach(mFragment);
}
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
// Do nothing
}
}
The only thing I noticed was that on every orientation change, onTabUnselected() won't be called, but still onTabSelected() is called (so the current tab will be attached twice without being detached in between). If that's the problem, I do not know how to fix it. If that's not the problem, I do not know where to look. I would be glad if someone has a suggestion.
Sidenote: I'm using the Action Bar from ActionBarSherlock. The problem appears on all Android versions I tested with (2.3, 4.0, 4.1).
I am not sure but here are some steps you can follow
Take Bundle reference before your Activity onCreate() method.
Bundle b1;
In your onCreate() method , put the Bundle value in b1
#Override
public void onCreate(Bundle savedInstanceState) {b1=savedInstanceState;
............................
}
Use this b1 in your onTabSelected method as
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
Fragment mFragment = MyActivity.this.getSupportFragmentManager().findFragmentByTag(mTag);
if (b1!=null){
ft.detach(mFragment);
//and the rest code
................}
}
Its an conclusion , which I have concluded with my working with fragments, but I have not done it with TabListener. So tell me when you are done , or any other solution.
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.