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
Related
I have a fragment inside of a fragment. This setup works fine until you rotate the device. After you rotate the device the inner fragment does not show anymore.
I am calling the .show() method and I have a couple of log statements to display what's going on, and the fragment just doesn't show up after rotation.
Any idea on what I'm doing wrong?
Here's my code. The issue can be found in the private method displayTab():
public static class MyTabsListener<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;
private FragmentManager fm;
private Fragment fragmentJobListDetails;
private Fragment fragmentTrends;
public MyTabsListener(Activity activity, String tag, Class<T> clz, FragmentManager fragmentManager)
{
this(activity, tag, clz, null,fragmentManager);
}
public MyTabsListener(Activity activity, String tag, Class<T> clz, Bundle args, FragmentManager fragmentManager)
{
mActivity = activity;
mTag = tag;
mClass = clz;
mArgs = args;
fm = fragmentManager;
// 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.hide(mFragment);
ft.commit();
}
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft)
{
displayTab(tab, ft);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft)
{
if (mFragment != null)
{
ft.hide(mFragment);
//ft.remove(mFragment);
}
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft)
{
displayTab(tab, ft);
}
private void displayTab(Tab tab, FragmentTransaction ft)
{
fragmentJobListDetails = mActivity.getFragmentManager().findFragmentByTag("jobDetails");
fragmentTrends = mActivity.getFragmentManager().findFragmentByTag("trends");
if (fragmentJobListDetails != null && !fragmentJobListDetails.isDetached())
{
ft.hide(fragmentJobListDetails);
}
if (mFragment == null)
{
mFragment = Fragment.instantiate(mActivity, mClass.getName(), mArgs);
ft.add(android.R.id.content, mFragment, mTag);
}
else
{
if (mFragment == fragmentTrends)
{
System.out.println("fragments are equal");
System.out.println("equal. Fragment added? = " + mFragment.isAdded());
System.out.println("equal. Fragment detached? = " + mFragment.isDetached());
System.out.println("equal. Fragment visible? = " + mFragment.isVisible());
ft.show(fragmentTrends);
System.out.println("equal. Fragment added? = " + mFragment.isAdded());
System.out.println("equal. Fragment detached? = " + mFragment.isDetached());
System.out.println("equal. Fragment visible? = " + mFragment.isVisible());
}
ft.show(mFragment);
}
}
}// end MyTabsListener
And here's the output of my logs, after rotation:
11-25 09:17:24.895: I/System.out(14605): mFragment = TrendsPagerHolder{427a94a8 #1 id=0x1020002 trends}
11-25 09:17:24.895: I/System.out(14605): fragments are equal
11-25 09:17:24.895: I/System.out(14605): equal. Fragment added? = true
11-25 09:17:24.895: I/System.out(14605): equal. Fragment detached? = false
11-25 09:17:24.895: I/System.out(14605): equal. Fragment visible? = false
11-25 09:17:24.895: I/System.out(14605): equal. Fragment added? = true
11-25 09:17:24.895: I/System.out(14605): equal. Fragment detached? = false
11-25 09:17:24.895: I/System.out(14605): equal. Fragment visible? = false
Thanks!
I'm not sure what is wrong with the entire operation, but I use the following lines and it always works:
MyDialogFragment dialogFragment = new MyDialogFragment(data);
dialogFragment.show(getFragmentManager(), key);
Note that MyDialogFragment has two constructors one excepts the data the other is default (empty)
using the saveState and restoreState allow you to save the dialog state.
I hope this will work for you as well.
You need to override the default execution of configuration changes. You can do this by using the configChanges attribute of the activity tag in AndroidManifest. Read more about it here.
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 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);
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.