I have a multiple-dialog-fragment layout. In the large layout, I show them as dialogs and there's no problem:
fragment.show(fragmentManager, "fragment_dialog");
But in normal devices, I am using a fragment transaction and replace fragments as below:
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
transaction.replace(R.id.fragment_container, fragment).addToBackStack(null).commit();
The problem is that in normal devices, when I press the menu button twice (or more), the same fragment will be shown over the previous one. Is there a way to find out which fragment is visible right now and prevent it from opening again?
First of all, add tag to when you replace
transaction.replace(R.id.fragment_container, fragment, "fragment_foo")
.commit(); // etc
then make a control
if (fragmentManager.findFragmentByTag("fragment_foo") == null){
// do something
}
You can find fragment by tag:
if (fragmentManager.findFragmentByTag("fragment_dialog") == null) {
//show dialog here
}
// Replace fragmentCotainer with your container id
Fragment currentFragment = fragmentManager.findFragmentById(R.id.fragmentCotainer);
// Return if the class are the same
if(currentFragment.getClass().equals(fragment.getClass())) return;
Related
Here's my Flow/Structure:
Activity
Fragment
Same Fragment within it.
I have overriden removeCurrentFragment() method which does go back functionality by removing Fragment by ID as follows -
#Override
public void removeCurrentFragment() {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Fragment currentFrag = getSupportFragmentManager().findFragmentById(R.id.fragment);
if (currentFrag != null)
transaction.remove(currentFrag);
transaction.commit();
}
It seems, when this happens, as ID of both fragment is same, it creates blank view.
If more details are required, please feel free to ask in comments. I will edit question as per required details.
I thought it was related to remove fragment, But I made new fragment with separate XML, still I am having the same issue.
I have parent fragment with pagination (as I need horizontal page scroll) in it have the child fragment, when clicking on child fragment button new fragment is replaced so when it is removed the X and Y of the child fragment is also disturbed.
here is the before and after screenshot of the x and y axis of child fragment.
Before
After
can any one suggest what could be the issue?
You have to use a tag to load the Fragment, and then use that same tag again to remove it.
For example, to add the Fragment:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
fragmentManager.popBackStack(tag, androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE);
ft.setCustomAnimations(R.anim.enter, R.anim.exit);
ft.add(containerId, fragment, tag);
ft.addToBackStack(tag);
ft.commit();
To remove it, again use the same tag:
if (fragmentManager.findFragmentByTag(currentTag) != null) {
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.remove(fragmentManager.findFragmentByTag(currentTag));
ft.commit();
}
I would like to ask something about BackStackFragments. Let us suppose we have 2 buttons in an app. When each on them is clicked the a new fragment starts and shown in the screen.
if (buttonIndex == 0) {
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(android.R.id.content,new FirstFragment());
ft.addToBackStack("added first");
ft.commit();
} else if (buttonIndex == 1) {
FragmentTransaction ft1 = fragmentManager.beginTransaction();
ft1.replace(android.R.id.content,new SecondFragment());
ft1.setTransition(ft1.TRANSIT_FRAGMENT_OPEN);
ft1.addToBackStack("added second");
ft1.commit();
}
Now you see what is happening.But here is my question.
I click the first and the second button and both fragments are added in the
stack. No problem:). But if I click let's say the second button 3 times,
then the corresponding fragment will run 3 times as well. Meaning that
I have to click the back button 3 times so as to go back in the first fragment.
Is this supposed to be happening?
Regards,
Theo.
You can add a tag while add/replace a fragment. Then u should check if the same fragment is added once. if yes then remove the existing one.
FragmentTransaction ft = fragmentManager.beginTransaction();
Fragment prev = getFragmentManager().findFragmentByTag("FirstFragment");
if (prev != null) {
ft.remove(prev);
}
ft.replace(android.R.id.content,new FirstFragment(),"FirstFragment");
ft.addToBackStack("added first");
ft.commit();
A good example is shown here in DialogFragment implementation
I am using navigation drawer and it is simple to use. I am not providing the complete code but providing you detail which could be easy for you to understand my problem. I am using fragments these are about 8 in numbers and I am replacing them with one an other. But here comes a problem
I am replacing them on click event of the navigation drawer. but there are two main problems
After replacement , I can see the previous fragment in the background. does replace method just call the new fragment over it ? if yes then what should I do to old fragment not be visible in the background of my new fragment.
When I click navigation drawer Item , it loads the specific fragment successfully. but keeping in that fragment when I click to that specific item again it loads this fragment again and again. For example if drawer item num 3 opens fragment MyBook , then by clicking item num three 2 or many times would open fragment that much time.
So please some one answer me how to cure my app for such kind of actions which I described above.
I tried like this. Its working fine me
FragmentManager frgmanager = getFragmentManager();
frgmanager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
FragmentTransaction frgTransaction = frgmanager.beginTransaction();
if(subitem.equalsIgnoreCase("subitem")){
Frag1 frg1 =new Frag1(mCtx);
frgTransaction.replace(R.id.inflate_layout, frg1);
}else if(subitem1.equalsIgnoreCase("subitem1")){
Frag2 frg2 =new Frag2(mCtx);
frgTransaction.replace(R.id.inflate_layout, frg2);
}else{
Frag2 frg3 =new Frag3(mCtx);
frgTransaction.replace(R.id.inflate_layout, frg3);
}
frgTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
frgTransaction.commit();
you can use addtobackstack in fragmentstranstion object.like
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.bodyfragment, new AnotherFragment());
transaction.addtoBackStack(null).commit();
Use replace-method of FragmentTransaction instead of add (http://developer.android.com/guide/components/fragments.html#Transactions)
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.bodyfragment, new AnotherFragment());
transaction.commit();
To avoid re-instantiating the fragment, keep track of the current open fragment and only do a fragment transaction, if we next-to-be-opened fragment is a different one than the current.
This may achieved like the following:
class MyActivity ... {
private String currentFragment;
private void openNewFragment(Fragment fragment) {
String newFragment = fragment.getClass().getSimpleName();
if (newFragment.equals(currentFragment)){
// new fragment already shown
return;
}
// Fragment transaction etc here:
}
}
Note that this only compares fragments based in their class name. Sometimes this might not be unique, e.g. if there is a DetailFragment class which displays information about an entity. Which entities details to show may depend on intent arguments.
The above code however will then prevent opening DetailFragment for Entity=1 if currently details for Entity=2 are shown. For these scenarios the information about the fragment kept needs to be extended (e.g. storing a Reference or WeakReference to the fragment instance itself).
I am building a navigation drawer as designed by the google documentation however I have an issue where the fragment is not being replaced. http://developer.android.com/training/implementing-navigation/nav-drawer.html
When the app first loads, the default fragment is loaded.
Clicking on another item on the drawer list leaves an empty view
However on rotating the device, loads the fragment chosen.
public void selectNavActivty(int position){
// TODO Changing between the different screens selection
fragment = null;
switch (position) {
case 0:
fragment = OverLay.newInstance();
break;
case 1:
fragment = Dummy.newInstance();
break;
}
if(fragment != null) {
// attach added to handle viewpager fragments
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.content_frame, fragment).attach(fragment)
.addToBackStack(null);
trans.commit();
getFragmentManager().executePendingTransactions();
} else {
Log.d("Drawer Activity","Error in creating Fragment");
}
}
For navigation menu fragment transactions I use the following approach, this way the fragment will be added and placed on top.
String name = "myFragment";
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content_frame, fragment, name)
.commit();
Look up the attach() function. It follows a different fragment lifecycle.
Also make sure that your layout files framelayout is visible.
Modify your code as below:
if(fragment != null) {
// attach added to handle viewpager fragments
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.content_frame, fragment);
trans.addToBackStack(null);
trans.commit();
} else {
Log.d("Drawer Activity","Error in creating Fragment");
}
If the solution doesn't work for you, share the xml code along with your fragment code.
After adding Fragment it will be added to activity state and its view
will be added to defined Container view. But by attaching nothing will
be displayed if fragment was not already added to UI. It just attaches
to fragment manager. However if view was already added to a container
in UI and detached after that, by attaching it will be displayed again
in its container. Finally you can use attach and detach if you want to
destroy fragment View temporarily and want to display and build its
view on future without losing its state inside activity.
https://stackoverflow.com/a/18979024/3329488
My solution is to tag all the fragment with unique tag on fragment replacement. Make sure you also assign a unique tag to the default fragment during it creation. A more efficient way is to identify the fragment before you recreate the same one.
public void selectNavActivty(int position){
// TODO Changing between the different screens selection
FragmentManager fragmentManager = getSupportFragmentManager();
fragment = fragmentManager.findFragmentById(R.id.content_frame);
String fragmentTag = null;
switch (position) {
case 0:
fragmentTag = "case0Tag"; // please change to better tag name
break;
case 1:
fragmentTag = "case1Tag"; // please change to better tag name
break;
default:
Log.d("Drawer Activity","Error in creating Fragment");
return;
}
if (fragmentTag != null && !fragment.getTag().equals(fragmentTag))
fragmentManager.beginTransaction().replace(R.id.content_fragment, fragment, tag).commit();
}
In my case after rotating a device a blank fragment was shown. I understood that in an Activity.onCreate() I always called creating a blank Fragment and after that a needed one. So I changed it's behaviour to this:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
openEmptyFragment()
openAnotherFragment()
}
}
I recommend to check savedInstanceState != null before adding new fragments, as written in Why won't Fragment retain state when screen is rotated?.
I have two fragments, I need to keep them both but show and hide on button clicks.
I added the first fragment using:
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
mDishFragment = new DishFragment();
transaction.add(R.id.dish_fragment, mDishFragment, "DishFragment");
transaction.commit();
First fragment (DishFragment) has a button on clicking of which the code checks if "OrderSummaryFragment" exists(using findFragmentbyTag), if it does, it should show() it else add() a new one. here is the code:
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
if (getFragmentManager().findFragmentByTag("OrderSummaryFragment") == null) {
System.out.println("OrderSummaryFragment not found");
transaction.add(R.id.dish_fragment, mOrderSummaryFragment,"OrderSummaryFragment");
System.out.println("Orderfragment added");
transaction.addToBackStack(null);
transaction.commit();
}else{
System.out.println("OrderSummaryFragment found");
transaction.hide(mDishFragment);
transaction.show(mOrderSummaryFragment);
transaction.commit();
}
For the first time since "OrderSummaryFragment" doesn't exist, the code adds one and it is displayed. There is a back button on the "OrderSummaryFragment" pressing of which show() up the first fragment "DishFragment".
The second time, since we have already added the "Ordersummaryfragment" previously, the findFragmentByTag should return OrderSummaryFragment but it returns null instead.
Note: I am not using replace() cause I want to reuse both of these fragments.
Hope someone can help me out.
Your fragment should search for your fragments using the getSupportFragmentManager() instead of the getFragmentManager Method() in your if structure.
BTW, What is that R.id.dish_fragment object? A fragment? A container? It should be a container like a LinearLayout.